iOS-block三種類型詳解


Block有三種類型:__NSGlobalBlock,__NSStackBlock,__NSMallocBlock

問題:
Block有幾種類型呢?這幾種類型分別在什么情況下出現?
我們思考一下,__NSStackBlock在訪問外部變量時,會有什么問題? 

   我們在講block的本質的時候已經知道了,block的本質就是一個 OC 對象,那么既然它是一個 OC 對象,它就會有類型,本文就將講解block的三種類型.並都繼承於NSBlock
我們在講block的三種類型之前,先了解一下程序的內存分配情況,因為不同類型的block分配的內存也不同.

  • .text段 : 也稱代碼段,我們寫的代碼都存放在這里
  • .data區 : 也稱數據區,一般存放全局變量, __NSGlobalBlock存放在這里
  • 堆區 : 存放我們自己alloc出來的對象,動態分配內存,需要程序員自己申請內存,自己管理. __NSMallocBlock存放在堆區
  • 棧區 : 一般存放局部變量,不需要程序員管理,系統自動分配,自動銷毀,__NSStackBlock存放在棧區
     
    不同block類型的內存分配

一: __NSGlobalBlock
 結論: 沒有訪問 auto變量 的block 就是 __NSGlobalBlock

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        static int age = 10;
        void(^block)(void) = ^{
            NSLog(@"Hello, World! %d",age);
        };
        NSLog(@"%@",[block class]);
    }
    return 0;
}
控制台輸出:__NSGlobalBlock__

這個很好理解,不過多解釋

 

二: __NSStackBlock
結論:訪問了auto變量 的block 就是 __NSStackBlock

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 10;
        void(^block)(void) = ^{
            NSLog(@"Hello, World! %d",age);
        };
        NSLog(@"%@",[block class]);
    }
    return 0;
}
控制台輸出:__NSMallocBlock__

怎么打印的是__NSMallocBlock__,剛才不是說訪問了auto變量就是__NSStackBlock嗎?
因為這里我們使用的是ARC,在ARC環境下,Xcode編譯器再某些情況會默認幫我們做調用copy 變成堆block ,我們在Build Settings中把ARC設置成MRC,再來打印一下:

2018-08-30 17:37:09.846365+0800 block的類型[4318:3463149] __NSStackBlock__ 

這次打印的就是__NSStackBlock__

我們思考一下,__NSStackBlock在訪問外部變量時,會有什么問題? 

會出現野指針crash 所以在ARC壞境Xcode幫我們處理成了堆block(__NSMallocBlock__)防止出現釋放了還去訪問導致野指針crash

 

所以,為了避免出現這種情況,我們需要把block存儲在堆上,__NSMallocBlock就閃亮登場了.

三: __NSMallocBlock
結論: 當一個__NSStackBlock調用了copy操作,返回的就是一個__NSMallocBlock

思考:如果我們對__NSStackBlock 進行一次 copy操作,會發生什么變化呢?

 __NSStackBlock copy后

  

‼️注意

以上都是在MRC環境下
如果是在ARC環境下,編譯器會根據情況自動將棧上的block復制到堆上, 比如以下幾種情況:

  • 1. block作為函數返回值時

    block作為返回值編譯器會自動copy
  • 2.將block賦值給__strong指針時

    被強指針引用的block會自動copy
  • 3.block作為Cocoa API方法名含有UsingBlock的方法參數時

    UsingBlock

 

  • 4.block作為GCD API的方法參數時
        GCD API的方法參數
 

 

  •  5.block調用copy方法
 
三種類型block的內存存儲以及每一種類型的block調用copy后的結果如下所示:

 

 

 

總結:

  • 1:一共有三種類型的Block.分為__NSGlobalBlock,__NSStackBlock,__NSMallocBlock.
    1. 沒有訪問 auto變量 的block 就是 __NSGlobalBlock
    2. 訪問了auto變量 的block 就是 __NSStackBlock
    3. 當一個__NSStackBlock調用了copy操作,返回的就是一個__NSMallocBlocksing
  • 2:在ARC環境下,編譯器會自動把棧上的block copy到堆上



免責聲明!

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



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