block 對外部引用變量的處理


                              MRC 環境

一、靜態變量 和 全局變量   在加和不加  __block 都會直接引用變量地址。也就意味着 可以修改變量的值。在沒有加__block 參數的情況下。

  • 全局block 和 棧block 區別為 是否引用了外部變量,堆block 則是對棧block  copy 得來。對全局block copy 不會有任何作用,返回的依然是全局block。

二, 常量變量(NSString *a = @"hello";a 為常量變量,@“hello”為常量。)-----不加__block類型 block 會引用常量的地址(淺拷貝)。加__block類型 block會去引用常量變量(如:a變量,a = @"abc".可以任意修改a 指向的內容。)的地址。 

 

如果不加__block 直接在block 內部修改變量 ,會編譯報錯。block 內部改變量是 只讀的。

但是 就一定可以推斷  block 會深拷貝 該變量嗎??? 

對於常量 @“hello”  存儲在 內存中的常量區, 程序結束才會釋放 內存。  如:

NSString *str = @"hello";

    NSString *abcStr = @"hello";

編譯器會優化處理, str 和 abcStr 都會指向 常量區的@“hello” 地址。

    NSString *str = @"hello";
    void (^print)(void) = ^{
        NSLog(@"block=str======%p",str);
    }
     str = @"hello1";
    print();

block 會拷貝變量內容到自己的棧內存上,以便執行時可以調用。 但並不是對str 內容做了深拷貝,重新申請內存。

因為str 是棧內存上的變量,指向 一個常量區的@“hello”. 編譯器做的優化是   當block 去拷貝str 指向內容時發現是個常量,

所以會去引用 @“hello” 的指針,沒必要再取申請一塊內存。

 

三、對象變量 如(MyClass *class、Block block)。 這里block 也是”類“對象(類似對象,其包含isa指針,clang 反編譯可以查看。因為它不像從NSObject 繼承下來的對象都支持 retain、copy、release)。

下面直接引用文章里總結的,經驗證無誤。

Block的copy、retain、release操作

不同於NSObjec的copy、retain、release操作:

  • Block_copy與copy等效,Block_release與release等效;
  • 對Block不管是retain、copy、release都不會改變引用計數retainCount,retainCount始終是1;
  • NSGlobalBlock:retain、copy、release操作都無效;
  • NSStackBlock:retain、release操作無效,必須注意的是,NSStackBlock在函數返回后,Block內存將被回收。即使retain也沒用。容易犯的錯誤是[[mutableAarry addObject:stackBlock],在函數出棧后,從mutableAarry中取到的stackBlock已經被回收,變成了野指針。正確的做法是先將stackBlock copy到堆上,然后加入數組:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock類型對象。
  • NSMallocBlock支持retain、release,雖然retainCount始終是1,但內存管理器中仍然會增加、減少計數。copy之后不會生成新的對象,只是增加了一次引用,類似retain;
  • 盡量不要對Block使用retain操作。

文章鏈接:http://tanqisen.github.io/blog/2013/04/19/gcd-block-cycle-retain/

以下補充

棧block : 猜測》》》》會copy 內部引用的對象變量。(如何驗證 block copy 了外部變量......在block 執行前 釋放對象.)。

             但實際對兩種對象變量的操作為:

  •              MyClass *class : 棧block 並不會copy 對象變量,也不會retain 對象。而是直接引用了對象變量的地址。可以在blcok 執行前釋放對象驗證。(有點毀三觀啊) 
  •              Block block ( ”類“對象):不會對 block 做處理。如果block 是棧block ,執行時依然為棧block.     堆block 同理

    

堆block : 通過copy 棧block 獲得, 當向棧block copy 時。會對內部引用的對象變量如下處理。

  •               MyClass *class  :       block 會retain 內部引用的 對象變量,改變引用對象的內存計數。
  •               Block block( ”類“對象):   ”類“對象block 執行copy ,如果是棧block。如果為堆block 並不會對他copy 。

 

GCD block :會對內部引用的對象變量如下處理。

  •                MyClass *class: retain 內部引用的對象變量,改變引用對象的內存計數。
  •                Block block( ”類“對象):   ”類“對象block 執行copy 。

 

    dispatch_async(dispatch_get_main_queue(), ^{

    });

當然如果引用了外部棧block 變量,也會copy 棧block 到堆上。同時棧block 對其內部引用對象變量 重復前面的操作。

 這里不如說 GCD 里的 block是內部做了處理的堆block 。

 

以上結論均在 MRC 環境 的   viewDidLoad  方法中測試。

 

ARC環境下 

 雖然 ARC 環境下會對 棧block 做優化,當創建一個棧block 時默認返回一個 堆block 。但 並不是ARC 環境下沒有棧block 。

-(void)demo:(Block)blocka;

-(void)demo:(Block)blocka{    

    NSLog(@"==demo=====%@",blocka);

}

通過 方法參數傳遞的 block 就是 棧block。

 

 

 

由此引出 block 循環引用問題:

循環引用 成立的條件: 直接導致A  B 兩個對象相互強引用(retain,strong)、或者 間接導致 A B 兩個對象相互強引用。

直接循環引用:

ARC 環境。

 

ARC 中 LLVM 會監控對象引用情況,如果出現循環引用會waring.

第一個警告是間接循環引用。

  • ViewController -----retain--> Custom
  • Custom -------強引用--->CustomBlock(堆block,會retain 內部引用對象變量)
  • CustomBlock  ---retain--------->self(ViewController)

第二個警告 直接循環引用。

  • ViewController --強引用------>Block(堆block,會retain 內部引用對象變量)
  • Block------retain--------->self(ViewController)

對於第三個 我們常用的GCD block 中,則沒有出現警告。雖然 gcd block 同樣對self 進行了retain.

  dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"====%@",self);
    });
    

但是self 並沒有直接或間接的去強引用 gcd block。 可以想象 gcd block 會統一被管理在GcdBlockDispatchCenter(這個是我瞎扯的,相當於GCD block 調度中心 來管理,反正不是self 。)。

 

還有一種情況下不會出現循環引用 如: ARC 環境

2014-12-30 11:05:59.119 Test_Class[4235:230795] ==demo=====<__NSStackBlock__: 0x118600>

上面說到,棧block 並不會對內部引用對象變量 retain .而是直接引用對象變量地址。、、

  • 這里 self 和  Custom 並沒有對 方法參數blocka 做任何引用操作,blocka 一直存在於棧上,直到執行完畢被釋放掉。
  • 當然blocka 也沒有對self  做任何操作,直接引用了地址。

 

以上 也就是說只有堆block 才會存在循環引用的情況。

 

》》待續.....

 

 

 

 

復習下內存分類:    http://blog.csdn.net/u011848617/article/details/39346075


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM