深刻學習block

 

首先,什麼是block:block其實就是一個代碼塊,把你想要執行的代碼封裝在這個代碼塊裏,等到須要的時候再去調用。那block是OC對象嗎?答案是確定的程序員

作一道很簡單的關於block的測試題。:面試

1 //
2     int (^testBlock) (int) = ^(int num) {
3         return num++;
4     };
5     NSLog(@"%d", testBlock(testBlock(testBlock(3))));

這道題是我公司面試題中的一道,來面試的都是至少兩年工做經驗的,可是很鬱悶,這道題絕大多數人寫的都是6。。正確結果爲:3。app

如下講解的內容均是ARC環境下。函數

1、block的分類
  • NSStackBlock:棧block
  • NSMallocBlock:堆block
  • NSGlobalBlock:全局block

1.NSStackBlock:
特色:生命週期由系統控制,函數返回即銷燬
用到局部變量、成員屬性\變量,且沒有強指針引用的block都是棧block
//棧block
    int i = 0;
    NSLog(@"%@",^{NSLog(@"%d",i);});//輸出結果 __NSStackBlock__: 0x7fff57aada78>
注意:不是沒有強指針(copy或strong)引用的block,就是棧block,也有多是全局block(下面會介紹什麼是全局block)。
 
2.NSMallocBlock:
特色:沒有強指針引用即銷燬,生命週期由程序員手動管理
棧block若是有強指針引用或copy修飾的成員屬性引用就會被拷貝到堆中,變成堆block
//堆block
     int j = 0;
    void(^mallocBlock)() = ^ {
        NSLog(@"%d",j);
    };
    NSLog(@"%@",mallocBlock);//輸出結果 <__NSMallocBlock__: 0x7f8cd351db80>
上面代碼也沒用看到strong 或 copy修飾符,可是爲何會強引用的,由於在ARC環境下,咱們在聲明變量的時候,前面是會被默認加上 __strong 修飾符的。因此咱們在ARC下聲明的Block通常都是堆block。
 
3.NSGlobalBlock: 
特色:命長,有多長?很長很長,人在塔在(應用程序在它就在)
沒有用到外界變量,或者只用到全局變量、靜態(static)變量的block就是全局block
對於全局block,用weak,strong,仍是copy修飾都是能夠的。(但最好不用用weak)
//全局block
    void (^globalBlock) () = ^ {
        NSLog(@"%d",staticNum);
    };
    NSLog(@"%@",globalBlock); //輸出結果 <__NSGlobalBlock__: 0x108152110>

注意:若是block中沒有用到外界變量,無論他是用什麼修飾符修飾,他都是全局block!測試

例如:spa

void (^global2Block) () = ^ {
        NSLog(@"globalBlock");
    };
    NSLog(@"%@",global2Block); // 輸出結果 <__NSGlobalBlock__: 0x1023a0150>

 

2、block對外界變量的捕獲指針

1.1 基本數據類型:局部變量code

     block會拷貝該變量的值當作常量使用,外界修改變量的值不會影響block內部,且block內部不能對其修改xml

     block內部修改外界變量i的值直接報錯,若是想要修改,能夠在int a = 0前面加上關鍵字__block,此時i等效於全局變量或靜態變量對象

  int a = 0;
    void (^block1)() = ^ {
//        a++ 直接修改a會報錯
        NSLog(@"a = %d",a);
    };
    a++;
    block1(); //輸出結果 a = 0;
    
    __block int b = 0;
    void (^block2) () = ^ {
        NSLog(@"b = %d",b); // 輸出結果 b = 0;
        b = 2;
    };
    block2();
    NSLog(@"b = %d",b); //輸出結果 b = 2;

1.2 基本數據類型:成員變量(實例變量),靜態變量,全局變量

   block直接訪問變量地址,在block內部能夠修改變量的值,而且外部變量被修改後,block內部也會跟着變

self.num = 1;
    self.num ++;
    void (^block3) () = ^ {
        self.num++;
    };
    block3();
    NSLog(@"%d",self.num);//輸出結果爲 3

 2.1 指針類型: 局部變量

     block會複製一份指針並強引用指針所指對象,且內部不能修改指針的指向,可是能夠修改指針所指向對象的值

  NSMutableString *str = @"abc".mutableCopy;
    void (^block4) () = ^ {
//        str = @"def"; 報錯
        [str appendString:@"def"];
        NSLog(@"str = %@",str);
    };
    str = @"123".mutableCopy;
    block4(); //輸出結果爲 "adbdef"

2.2 指針類型: 成員變量(實例變量),靜態變量,全局變量

     block不會複製指針,可是會強引用該對象,內部可修改指針指向,block會強引用成員屬性\變量所屬的對象,這也是爲何block內部用到self.xxx_xxx可能會引發循環引用的緣由

static NSString *staticStr = @"abc";
    void (^block5) () = ^ {
        NSLog(@"staticStr = %@",staticStr);
        staticStr = @"def";
        NSLog(@"staticStr = %@",staticStr);
    };
    staticStr = @"123";
    block5();
    //輸出結果爲 staticStr = 123  staticStr = def
相關文章
相關標籤/搜索