Block的分類編程
1 // mian thread [block copy] 2 int a = 10; // 捕獲外部變量 3 void(^block)(void) = ^{ 4 5 NSLog(@"hello block %d",a); 6 }; // 匿名函數 7 8 block(); 9 10 NSLog(@"%@",block); // 萬物皆對象,block也是對象 RAC: 萬物皆signal 11 12 // block 分類 13 // NSGlobalBlock : 靜態區 (沒有int a) 14 // NSMallocBlock : 堆Block (定義int a後) 15 // NSStackBlock : 棧Block 16 17 NSLog(@"第三種Block %@",^{ 18 NSLog(@"%d",a); 19 });
假設A控制器跳轉至TargetViewController, 若是目標控制器內有block形成循環應用, 當從TargetViewController返回時, TargetViewController不會調用析構方法(dealloc方法). 這就形成了內存泄漏. 下面列出三種方法消除循環引用.vim
1 #import "TargetViewController.h" 2 3 // typedef void(^LHBlock)(void); 4 typedef void(^LHBlock)(TargetViewController *); 5 6 @interface TargetViewController () 7 8 /** 說明 */ 9 @property (nonatomic, copy) LHBlock block; 10 /** 說明 */ 11 @property (nonatomic, copy) NSString *name; 12 13 @end 14 15 @implementation TargetViewController 16 17 - (void)viewDidLoad { 18 [super viewDidLoad]; 19 20 self.view.backgroundColor = [UIColor whiteColor]; 21 22 self.name = @"my name"; 23 24 // 使用__weak,就是告訴系統,這是個循環應用,因此不用調用,就會釋放 25 // __weak typeof(self) weakSelf = self; 26 // self.block = ^{ 27 // NSLog(@"%@",weakSelf.name); 28 // // 延長壽命週期,strong 29 // }; 30 31 32 // 要在block裏面置爲nil,而且必須調用,不然不會置爲nil,仍是會形成循環應用 33 // __block TargetViewController *weakVC = self; // 從新拷貝一份 34 // self.block = ^{ 35 // NSLog(@"%@",weakVC.name); 36 // weakVC = nil; 37 // }; 38 // self.block(); 39 40 // 爲何會產生循環引用 41 // self -> block -> vc 42 // 這樣不會產生循環應用,vc只是臨時變量,只在做用域內有效,出來就釋放了 43 self.block = ^(TargetViewController *vc) { 44 NSLog(@"%@",vc.name); 45 }; 46 // 調不調用block都會走析構方法 47 self.block(self); 48 49 } 50 51 - (void)dealloc { 52 NSLog(@"dealloc"); 53 } 54 55 @end
經過終端編譯出block運行時所執行的代碼.異步
1.建立出block.c的文件函數
vim: 進入編輯模式atom
輸入":"進入輸入臺spa
wq: 保存並退出vim模式3d
2.在block.c的文件中輸入以下代碼:指針
1 #include "stdio.h" 2 int main () { 3 4 int a = 10; 5 6 void(^block)(void) = ^{ 7 8 printf("%d",a); 9 }; 10 11 block(); 12 13 return 0; 14 }
3. 終端輸入, 多出a.out文件, 能夠執行運行結果.code
1 gcc block.c orm
4. 終端繼續輸入, 生成編譯代碼.
1 clang -rewrite-objc block.c
最終結果以下:
雙擊打開block.cpp文件.
5. 上面是消息轉發,看不懂. 一直往下翻往下翻,翻到570行左右.
看出main函數的執行操做
看出a值是經過值拷貝,拷貝到block中.
看出block也是對象,符合對象的規定,有isa指針.
6. 一樣的步驟,將block.c中的代碼修改成:(__block)
1 #include "stdio.h" 2 int main () { 3 4 __block int a = 10; 5 6 void(^block)(void) = ^{ 7 8 printf("%d",a); 9 }; 10 11 block(); 12 13 return 0; 14 }
查看block.cpp文件,發現block中的操做有些不一樣:
這就是爲何加了__block就有了修改變量的權限.
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 4 // block應用: 鏈式編程+函數編程 5 // 經過點語法,串聯操做 6 // 返回值block 7 NSLog(@"%@",self.select.where(@"all 牛")); 8 9 // get方法 + 參數 10 // viewDidLoad : 數據 --> 方法:sel(方法選擇器) --> imp --> 函數 11 // 方法: 函數 : 給某個對象發送消息 _cmd 12 13 // block 參數 14 // 函數式: y = f(x) ---> y = f(f(x)) 15 16 [self functionBlock:^(NSString *word) { 17 NSLog(@"%@",word); 18 }]; 19 20 } 21 22 #pragma mark - 函數式Demo 23 - (void)functionBlock:(void(^)(NSString *))success { 24 if (success) { 25 // 靈活 異步 26 success(@"hello 函數式"); 27 } 28 } 29 30 #pragma mark - 鏈式Demo 31 - (ViewController *)select { 32 NSLog(@"select"); 33 return self; 34 } 35 36 - (NSString *(^)(NSString *))where { 37 NSLog(@"where"); 38 39 NSString *(^block)(NSString *) = ^(NSString *word) { 40 return [NSString stringWithFormat:@"ken:%@",word]; 41 }; 42 43 return block; 44 }
這裏只是block初探,有興趣能夠深刻研究.