最近在玩node.js跟android SDK的時候,也發現有這種類似的寫法
所以就花了一點時間,研讀前輩的文章跟水果官方技術文件
然後整理出一些心得...
這篇文章在一開始,會先介紹block的宣告與使用方式
接下來,將會用兩個例子,把block當成物件丟到某個method裡面 (類似匿名function的概念)
最後,再用兩個例子來實驗block的性質:可存取block外部的變數
這篇文章暫時不講記憶體管理的部份...
block宣告與使用方式
-(void)blockSample1 {
NSLog(@"exec blockSample1 method");
// 第一種方式
// 宣告一個myBlock型態為: 傳入兩個int, 回傳一個NSString*
typedef NSString* (^myBlock)(int, int);
// 類似int a; 或是float b;
myBlock block1;
// 實作block1的內容
block1 = ^(int x, int y) {
NSLog(@"[BLOCK1] running");
return [NSString stringWithFormat:@"%d * %d = %d", x, y, x*y];
};
// 第二種方式
// 不事先定義type,直接實作它
// block為: 傳入兩個int, 回傳一個NSString*
NSString* (^block2)(int, int) = ^(int m, int n) {
NSLog(@"[BLOCK2] running");
return [NSString stringWithFormat:@"%d * %d = %d", m, n, m*n];
};
// 使用block
NSLog(@"block1 returned: [%@]", block1(2,3));
NSLog(@"block2 returned: [%@]", block2(6,7));
}
執行結果如下:2012-12-03 15:30:32.621 BlockTest[21129:303] exec blockSample1 method 2012-12-03 15:30:32.622 BlockTest[21129:303] [BLOCK1] running 2012-12-03 15:30:32.622 BlockTest[21129:303] block1 returned: [2 * 3 = 6] 2012-12-03 15:30:32.622 BlockTest[21129:303] [BLOCK2] running 2012-12-03 15:30:32.623 BlockTest[21129:303] block2 returned: [6 * 7 = 42]
把block丟到某個method裡面執行
例子A:
此method傳入一個block變數, 這個block有兩個int傳入, 一個int回傳
下面是method的實作內容
-(void)blockSample2:(int(^)(int, int))aBlock {
NSLog(@"exec blockSample2 method");
int a = 5;
int b = 3;
// 使用block
// 傳入5,3, 回傳一個int
// 不管block裡面的實作。
int result = aBlock(5, 3);
NSLog(@"aBlock(%d, %d) result: [%d]", a, b, result);
}
在呼叫此method時,可以直接把block實作出來,然後當做一個物件傳進去
// 傳入一個block的實作到blockSample2 method
// blockSample2的宣告如下
// -(void)blockSample2:(int(^)(int, int))aBlock;
[obj blockSample2:^int(int a, int b) {
NSLog(@"[BLOCK] exec block...");
NSLog(@"[BLOCK] find a:%d, b:%d", a, b);
return a-b;
}];
執行結果如下:2012-12-03 15:30:32.624 BlockTest[21129:303] exec blockSample2 method 2012-12-03 15:30:32.624 BlockTest[21129:303] [BLOCK] exec block... 2012-12-03 15:30:32.625 BlockTest[21129:303] [BLOCK] find a:5, b:3 2012-12-03 15:30:32.625 BlockTest[21129:303] aBlock(5, 3) result: [2]
例子B:
此method傳入一個block變數, 這個block沒有任何傳入跟回傳值
下面是method的實作內容
-(void)blockSample3:(void(^)(void))aBlock {
NSLog(@"exec blockSample3 method");
aBlock();
}
在呼叫此method時,可以直接把block實作出來,然後當做一個物件傳進去
// 傳入一個block的實作到blockSample3 method
// block型態:無傳入值,無回傳值
// 此時,block實作可以簡寫成 ^{}
// blockSample3的宣告如下
// -(void)blockSample3:(void(^)(void))aBlock;
[obj blockSample3:^{
NSLog(@"[BLOCK] exec block...");
}];
執行結果如下:2012-12-03 15:30:32.626 BlockTest[21129:303] exec blockSample3 method 2012-12-03 15:30:32.626 BlockTest[21129:303] [BLOCK] exec block...這種用法以後會特別常見,尤其在GCD...
另外,現在新的presentViewController:animated:completion:方法,也使用block來處理callback了
下面是method的宣告
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion;
block可讀取外部變數的性質
直接看code吧...
-(void)blockSample4 {
NSLog(@"exec blockSample4 method");
int out_of_block_var = 10;
// 實作 block
NSString* (^block)(int) = ^(int block_local_var) {
NSLog(@"[BLOCK] running");
// 在block內可讀取block外的變數,但是是唯讀的
NSLog(@"[BLOCK] find out var %d, in var %d", out_of_block_var, block_local_var);
return [NSString stringWithFormat:@"%d - %d = %d",
out_of_block_var, block_local_var, out_of_block_var - block_local_var];
};
// 使用 block
NSLog(@"block2 returned: [%@]", block(8));
}
// block可寫入外部變數,但是要加上__block
// 感覺有點像java的final
-(void)blockSample5 {
NSLog(@"exec blockSample5 method");
__block int out_of_block_var = 10;
NSLog(@"out_of_block_var: %d", out_of_block_var);
// 實作 block
NSString* (^block)(int) = ^(int block_local_var) {
NSLog(@"[BLOCK] running");
NSLog(@"[BLOCK] find out var %d, in var %d", out_of_block_var, block_local_var);
// 將外部變數改成 8 (寫入8到外部變數)
NSLog(@"[BLOCK] modify out var to \"8\"");
out_of_block_var = 8;
NSLog(@"[BLOCK] find out var %d, in var %d", out_of_block_var, block_local_var);
return [NSString stringWithFormat:@"%d - %d = %d",
out_of_block_var, block_local_var, out_of_block_var - block_local_var];
};
// 使用 block
NSLog(@"block2 returned: [%@]", block(8));
NSLog(@"out_of_block_var: %d", out_of_block_var);
}
執行結果如下:
2012-12-03 15:30:32.627 BlockTest[21129:303] exec blockSample4 method 2012-12-03 15:30:32.628 BlockTest[21129:303] [BLOCK] running 2012-12-03 15:30:32.628 BlockTest[21129:303] [BLOCK] find out var 10, in var 8 2012-12-03 15:30:32.628 BlockTest[21129:303] block2 returned: [10 - 8 = 2] 2012-12-03 15:30:32.629 BlockTest[21129:303] exec blockSample5 method 2012-12-03 15:30:32.630 BlockTest[21129:303] out_of_block_var: 10 2012-12-03 15:30:32.630 BlockTest[21129:303] [BLOCK] running 2012-12-03 15:30:32.630 BlockTest[21129:303] [BLOCK] find out var 10, in var 8 2012-12-03 15:30:32.631 BlockTest[21129:303] [BLOCK] modify out var to "8" 2012-12-03 15:30:32.631 BlockTest[21129:303] [BLOCK] find out var 8, in var 8 2012-12-03 15:30:32.631 BlockTest[21129:303] block2 returned: [8 - 8 = 0] 2012-12-03 15:30:32.632 BlockTest[21129:303] out_of_block_var: 8
One more thing...
這東西我有放在GitHub
有需要的請自取
Block在iOS的殺手及應用,GCD
作者外出取材,等我有空再寫...XD 讓我富姦一下,科科~
(富姦:躺著也中槍)
沒有留言:
張貼留言