最近在玩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 讓我富姦一下,科科~
(富姦:躺著也中槍)
沒有留言:
張貼留言