Ради потомства / полноты ... Вот два ПОЛНЫХ примера того, как реализовать этот смехотворно универсальный «способ делать вещи». Ответ Роберта блаженно лаконичен и точен, но здесь я также хочу показать, как на самом деле «определить» блоки.
@interface ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end
@implementation ResusableClass
static NSString const * privateScope = @"Touch my monkey.";
- (CALayer*(^)(NSArray*)) layerFromArray {
return ^CALayer*(NSArray* array){
CALayer *returnLayer = CALayer.layer
for (id thing in array) {
[returnLayer doSomethingCrazy];
[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];
}
return list;
};
}
@end
Глупый? Да. Полезно? Ада, да. Вот другой, более "атомарный" способ установки свойства ... и класс, который до смешного полезен ...
@interface CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end
@implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
@end
Это иллюстрирует установку свойства блока через аксессор (хотя и внутри init, с сомнительной рискованной практикой ...) по сравнению с «неатомным» механизмом «получения» первого примера. В любом случае… «жестко закодированные» реализации всегда могут быть перезаписаны, за экземпляр .. a lá ..
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Кроме того ... если вы хотите добавить свойство блока в категорию ... скажем, вы хотите использовать блок вместо какой-то "старой" цели / действия старой школы ... Вы можете просто использовать соответствующие значения для: хорошо .. связать блоки.
typedef void(^NSControlActionBlock)(NSControl*);
@interface NSControl (ActionBlocks)
@property (copy) NSControlActionBlock actionBlock; @end
@implementation NSControl (ActionBlocks)
- (NSControlActionBlock) actionBlock {
// use the "getter" method's selector to store/retrieve the block!
return objc_getAssociatedObject(self, _cmd);
}
- (void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
self, @selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self; // set self as target (where you call the block)
self.action = @selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {
if (self.actionBlock && self.target == self) self.actionBlock(self);
}
@end
Теперь, когда вы делаете кнопку, вам не нужно настраивать какую-то IBAction
драму. Просто свяжите работу, которую нужно выполнить при создании ...
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
Этот шаблон может быть применен OVER и OVER к API Какао. Используйте свойства, чтобы свести соответствующие части вашего кода ближе друг к другу , исключить запутанные парадигмы делегирования и использовать силу объектов, выходящую за рамки простого действия в качестве тупых «контейнеров».