I really like the way blocks work and thought it would be nice to add them in a few place like setting the action for UIRefreshControl
.
So I created a category
to UIRefreshControl
@interface UIRefreshControl (Blocks)
@property (nonatomic, copy) void (^actionBlock)();
- (id)initWitActionBlock:(void (^)())actionBlock;
@end
@implementation UIRefreshControl (Blocks)
- (id)initWitActionBlock: (void (^)())actionBlock {
self = [super init];
if (self) {
self.actionBlock = [actionBlock copy];
[self addTarget:self action:@selector(fireActionBlock) forControlEvents:UIControlEventValueChanged];
}
return self;
}
- (void)fireActionBlock {
self.actionBlock();
}
@end
Which is crashing : reason: '-[UIRefreshControl setActionBlock:]: unrecognized selector sent to instance
But I really don't know blocks that much and also I don't really see the difference between this category
and a subclass
doing the same thing.
I think I don't fully understand what's happening with properties, so my questions are what should I do ? And if it's possible, is this okay ? Or maybe I shouldn't be doing this ever ?
EDIT : *The solution with associated reference thanks @Martin R!
static char const * const ActionBlockKey = "ActionBlockKey";
@interface UIRefreshControl (Blocks)
@property (nonatomic, copy) void (^actionBlock)();
- (id)initWitActionBlock:(void (^)())actionBlock;
@end
@implementation UIRefreshControl (Blocks)
@dynamic actionBlock;
- (id)initWitActionBlock: (void (^)())actionBlock {
self = [super init];
if (self) {
self.actionBlock = [actionBlock copy];
[self addTarget:self action:@selector(fireActionBlock) forControlEvents:UIControlEventValueChanged];
}
return self;
}
- (void)fireActionBlock {
self.actionBlock();
}
- (id)actionBlock{
return objc_getAssociatedObject(self, ActionBlockKey);
}
- (void)setActionBlock:(void (^)())actionBlock{
objc_setAssociatedObject(self, ActionBlockKey, actionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
The problem is unrelated to blocks.
The compiler does not synthesize properties defined in a class category, because that would require a corresponding instance variable, and you cannot add instance variables in a class category.
Actually you should get a warning like
property 'actionBlock' requires method 'actionBlock' to be defined - use @dynamic or provide a method implementation in this category
I would recommend to create a subclass instead.