Block探究

知識點:

  • Block初探
  • Block循環引用
  • Block底層原理
  • Block應用進階

 

一. Block初探

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     });

 

二. Block循環引用

假設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底層原理

經過終端編譯出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就有了修改變量的權限.

 

四. 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初探,有興趣能夠深刻研究.

相關文章
相關標籤/搜索