用OBJC編程 7 - Working with Blocks
Block 是語言級別的特性。它是一個OBJC的對象,可以被加入容器如NSArray或NSDictionary。它可以捕獲所處作用域的數值,非常類似其它語言的closure或者lambda。語法^{
NSLog(@"This is a block");
}
可以像函數指針那樣聲明一個變量來持有這個blockvoid (^simpleBlock)(void);
simpleBlock = ^{
NSLog(@"This is a block");
}; // 注意這里有一個分號
也可以這樣寫void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
調用這個blocksimpleBlock();
帶上參數和返回值^double (double firstValue, double secondValue){
return firstValue*secondValue;
}
// ,,,,,,,,,,,
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) { // 返回值類型可以省略
return firstValue*secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);
捕獲Enclosing Scope內的值,一旦捕獲,這個值就不會變化,即便后續改變這個值-(void)testMethod{
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
}
anInteger = 84;
testBlock(); // 仍然輸出42
}
使用__block__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84:
testBlock(); // output 84;
// ,,,,,,,,,,,,,
_block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger); // output 42
anInteger = 100;
};
testBlock();
NSLog(@"Value of original variable is now: %i", anInteger); // output 100;
通過參數傳遞Block,例如實現一個回調-(IBAction)fetchRemoveInformation:(id)sender{
[self showProgressIndicator];
XYZWebTask *task = //,,,
[task beginTaskWithCallbackBlock:^{
[self hideProgressIndicator];
}];
}
// beginTaskWithCallbackBlock 的定義是這樣的
-(void)beginTaskWithCallbackBlock:(void)(^)(void))callbackBlock{
//,,,
callbackBlock();
}
最佳實踐是將block作為最后一個參數,這樣便于閱讀。也可以使用typedef簡化語法typedef void (^XYZSimpleBlock)(void);
//,,,,,,,,,,,,,,,
XYZSimpleBlock anotherBlock = ^{ /*,,,*/ };
//,,,,,,,,,,,,
-(void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock{
//,,,,
callbackBlock();
}
可以將block作為屬性@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void); // 必須使用copy
@end
//,,,,,,,,,,,,,,
self.blockProperty = ^{ /* ,,, */ };
self.blockProperty();
避免強引用循環在block里捕獲self,諸如在一個callback block里,會引入內存管理問題。block會會維護一個捕獲對象的強引用,包括self@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
////////////////////////
@implementation XYZBlockKeeper
-(void)configureBlock{
self.block = ^{
[self doSomething]; // 捕獲了一個self的強引用
// 建立了一個強引用循環
}
}
@end
上述代碼會產生一個編譯警告,為了避免這種情況,最佳實踐是捕獲一個self的弱引用-(void)configureBlock{
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^ {
[weakSelf doSomething];
};
}
block可以簡化枚舉(略)block可以簡化并發任務(略)