Block的認識和使用,Block認識使用

來源:互聯網
上載者:User

Block的認識和使用,Block認識使用

Blocks是Objective-C的匿名函數。block是iOS在4.0之後新增的程式文法。

Blocks有三種類型,_NSConcreteGlobalBlock,_NSConcreteStackBlock和_NSConcreteMallocBlock。

1._NSConcreteGlobalBlock 全部的靜態block,不會訪問任何外部變數。

2._NSConcreteStackBlock 儲存在棧中的block,當函數返回時會被銷毀。

3._NSConcreteMallocBlock 儲存在堆中的block,當引用計數為0時會被銷毀。

變數的複製

對於block外的變數引用,block預設是將其複製到其資料結構中來實現訪問的,如所示(圖片來自這裡):


#define TLog(prefix,Obj) {NSLog(@"變數記憶體位址:%p,變數值:%p,指向對象值:%@, --> %@",&Obj,Obj,Obj,prefix);}

上面為定義的宏變數

下面為代碼:

NSString*a =@"100";

    TLog(@"a-->non block", a);

    void(^block2)(void) = ^{

        TLog(@"a-->block", a);

    };

    a = @"102";

    block2();

    a = nil;

block2();

列印結果為:

變數記憶體位址:0x7fff570d3b28,變數值:0x108b2c190,指向對象值:100,--> a-->non block

變數記憶體位址:0x7ff8bb533d00,變數值:0x108b2c190,指向對象值:100,--> a-->block

變數記憶體位址:0x7ff8bb533d00,變數值:0x108b2c190,指向對象值:100,--> a-->block

說明外部變數被copy到block中,外面變數的變化,不會引起block內的變數變化。兩個不是同一個變數了。同時外部變數不可以在block中做修改。

__weak修改代碼如下:

__weak NSString *b =@"123";

    TLog(@"b-->non block", b);

    void(^blocka)(void) = ^{

        TLog(@"c-->block", b);

    };

 

    blocka();

    b = nil;

    TLog(@"b-->1", b);

blocka();

列印結果如下:

變數記憶體位址:0x7fff57ddcb28,變數值:0x107e23190,指向對象值:123,--> b-->non block

變數記憶體位址:0x7fb95ae2dd10,變數值:0x107e23190,指向對象值:123,--> c-->block

變數記憶體位址:0x7fff57ddcb28,變數值:0x0,指向對象值:(null),--> b-->1

變數記憶體位址:0x7fb95ae2dd10,變數值:0x107e23190,指向對象值:123,--> c-->block

__weak修飾,整個內容copy,所以b = nil,不會影響到block內部。

 

對於用__block修飾的外部變數引用,block是複製其引用地址來實現訪問的,如所示(圖片來自這裡):


__blockNSString*a =@"100";

    TLog(@"a-->non block", a);

    void(^block2)(void) = ^{

        TLog(@"a-->block", a);

    };

    a = @"102";

    block2();

    a = nil;

block2();

列印結果為:

變數記憶體位址:0x7fff54e04b28,變數值:0x10adfb1a0,指向對象值:100,--> a-->non block

變數記憶體位址:0x7ff52a604078,變數值:0x10adfb220,指向對象值:102,--> a-->block

變數記憶體位址:0x7ff52a604078,變數值:0x0,指向對象值:(null),--> a-->block

用__block修飾的變數,只是進行指標的copy,所以當外部變數修改時也影響了block內部的變化。和用static修飾的效果一樣。可以在block內部對外部變數進行修改。

怎麼避免block的循環參考

NSString *a = [[NSStringalloc]initWithFormat:@"%d",123];

  

    TLog(@"a", a);

    __weakNSString *b = a;//b只是進行了a的指標copy,所以a的值變化也會影響到b。同時a釋放時,b也釋放了。

    TLog(@"b-->non block", b);

    void(^blocka)(void) = ^{

        TLog(@"b-->block", b);

    };

    

    blocka();

    a = nil;

blocka();

列印結果如下:

變數記憶體位址:0x7fff53db5b28,變數值:0x7fd4b8f1a210,指向對象值:123,--> a

變數記憶體位址:0x7fff53db5b20,變數值:0x7fd4b8f1a210,指向對象值:123,--> b-->non block

變數記憶體位址:0x7fd4b8f17b50,變數值:0x7fd4b8f1a210,指向對象值:123,--> b-->block

變數記憶體位址:0x7fd4b8f17b50,變數值:0x0,指向對象值:(null),--> b-->block

從上面的結果可以看到

·      block 內的b 和外部的 b 並不是同一個變數(內容copy)

·      block 捕獲了b 同時也是對 a 進行了弱引用,當我在 block 外把 a 釋放了之後,block 內也讀不到這個變數了

·      當a 賦值 nil 時,block 內部的 b 也為 nil 了,也就是說 a實際上是被釋放了,可見 __weak 是可以避免循環參考問題的

·      __weak 本身是可以避免循環參考的問題的,但是其會導致外部對象釋放了之後,block內部也訪問不到這個對象的問題,我們可以通過在 block 內部聲明一個 __strong 的變數來指向 weakObj,使外部對象既能在block 內部保持住,又能避免循環參考的問題

·      而使用__block

    MyObject*obj = [MyObjectnew];

    obj.text=@"123456";

    TLog(@"obj", obj);

    __blockMyObject*weakObj= obj;

    TLog(@"weakObj-->non block", weakObj);

    void(^block2)(void) = ^{

        TLog(@"weakObj-->block",weakObj);

    };

   

    block2();

    obj = nil;

·          block2();

·      列印結果如下:

變數記憶體位址:0x7fff5d723b28,變數值:0x7ff999c990e0,指向對象值:<MyObject:0x7ff999c990e0>, --> obj

變數記憶體位址:0x7fff5d723b20,變數值:0x7ff999c990e0,指向對象值:<MyObject:0x7ff999c990e0>, --> weakObj-->non block

變數記憶體位址:0x7ff999e3f098,變數值:0x7ff999c990e0,指向對象值:<MyObject:0x7ff999c990e0>, --> weakObj-->block

變數記憶體位址:0x7ff999e3f098,變數值:0x7ff999c990e0,指向對象值:<MyObject:0x7ff999c990e0>, --> weakObj-->block

當外部 obj 指向 nil 的時候,obj 理應被釋放,但實際上 blockObj 依然強引用著 obj,obj 其實並沒有被真正釋放。因此使用 __block並不能避免循環參考的問題。

__block 本身無法避免循環參考的問題,但是我們可以通過在 block 內部手動把 blockObj 賦值為 nil 的方式來避免循環參考的問題。另外一點就是 __block 修飾的變數在block 內外都是唯一的,要注意這個特性可能帶來的隱患。


參考連結http://blog.devtang.com/blog/2013/07/28/a-look-inside-blocks/http://honglu.me/2015/01/06/weak%E4%B8%8Eblock%E5%8C%BA%E5%88%AB/

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.