一個Block永遠是一個方法中的最后一個參數(shù)
最好的實踐就是在一個方法中只使用一個block參數(shù)墙基,如果這個方法同樣需要其他非block的參數(shù)残制,那么這個block需要放在最后。
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;
當指定的block內(nèi)嵌的時候颗祝,這種寫法會使得該方法閱讀起來更簡單,像下面這樣:
[self beginTaskWithName:@"MyTask" completion:^{
NSLog(@"this task is complete");
}];
使用類型定義來簡化block的語法
如果你需要定義多個相同簽名的block搁宾,你可能會為這個簽名定義一個你獨有的類型倔幼。
舉個例子來說,你可以為一個簡單的沒有任何變量和返回值的block定義一個類型翩腐,像下面這樣:
typedef void (^XYZSimpleBlock)(void);
然后你可以在這個方法參數(shù)中或者在創(chuàng)建block變量的時候膏燃,使用你的自定義類型:
XYZSimpleBlock anotherBlock = ^{
...
};
- (void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock {
...
callbackBlock();
}
自定義類型的定義實際上在處理blocks返回blocks或者獲取其他blocks作為參數(shù)的時候非常有用蹄梢。思考一下下面這個例子:
void (^(^complexBlock)(void(^)(void)))(void) = ^ (void (^aBlock)(void)) {
...
return ^ {
...
};
}
這個complexBlock變量指的是一個用其他block(aBlock)作為參數(shù)冰返回另一個block的block。重寫代碼來增加類型定義可讀性:
XYZSimpleBlock (^betterBlock)(XYZSimpleBlock) = ^(XYZSimpleBlock aBlock) {
...
return ^{
...
};
}
Objects使用屬性來持續(xù)跟蹤Blocks
用定義屬性來跟蹤block和一個block變量的語法很相似:
@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end
注意:你要使用copy來修飾這個屬性而咆,因為我們需要復制block來跟蹤它超出原始范圍的捕捉狀態(tài)幕袱。當使用自動引用計數(shù)的時候就不是一些你需要去擔心的事情,因為它會自動發(fā)生涯捻,但是對于這個屬性修飾來說最好的方式就是去展示行為結(jié)果障癌。
一個block屬性設(shè)置或者調(diào)用可以像任何其他block變量一樣:
self.blockProperty = ^ {
...
};
self.blockProperty();
同樣的可以用類型定義來對這個block屬性進行修飾轿亮,像下面:
typedef void (^XYZSimpleBlock)(void);
@interface XYZObject : NSObject
@property (copy) XYZSimple blockProperty;
@end
當捕捉self的時候避免強引用循環(huán)
如果你需要去在block中捕捉self的時候但骨,例如當定義一個callback的block补履,考慮內(nèi)存管理的影響很重要。blocks對任何被捕捉的對象都持有一個強引用,包括self野蝇,這意味著它很容易結(jié)束強引用周期乍狐,例如烫罩,一個對象持有一個捕捉self的并且具有copy的屬性的block:
@interface XYZSimpleBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
@implementation XYZBlockKeeper
- (void)configureBlock {
self.block = ^{
[self doSometing];
};
}
這個例子浊伙,編譯器會發(fā)出警告串结,但是一個更復雜的例子可能涉及多個對象之間的強引用來創(chuàng)建循環(huán)卧蜓,代碼將會變得更加難診斷盛霎。為了避免這個問題凤薛,最好的辦法就是捕捉一個self的弱引用,像下面這樣:
- (void)configureBlock {
XYZBlockKeeper *__weak weakSelf = self;
self.block = ^ {
[weakSelf doSomething];
}
}
通過捕捉self的弱指針,block將不會持有與XYZBlockKeeper對象的強引用關(guān)系。如果這個對象在block調(diào)用之前被釋放掉了,這個weakSelf指針將會很直接的就被重置成nil。