深入理解Block之Block的型別

發表於2016-08-21

iOS-Source-Code-Analyse 首發
Follow: sunbohong· Github

深入理解Block之Block的型別

當我在 2012 年剛剛開始從事 iOS 開發工作時,對 Block 的使用開始逐漸在 iOS 開發者中推廣開來(Block 的第一個穩定 ABI 版本是在 Mac OS X 10.6 被引入的。)。作為 iOS 開發中非常吸引我的一個特性,對其的深入分析自然必不可少。

重要宣告:雖然我已經仔細的檢查了自己的相關程式碼和相關的措辭,但是請不要盲目相信本文的正確性。我已經見過非常多的經驗開發者對於 Block 有錯誤的理解(我也不會例外)。請一定保持一顆懷疑的心。

型別簡介

對 block 稍微有所瞭解的人都知道,block 會在編譯過程中,會被當做結構體進行處理。 其結構Block-ABI-Apple大概是這樣的:

isa 指標會指向 block 所屬的型別,用於幫助執行時系統進行處理。

Block 常見的型別有三種,分別是 _NSConcreteStackBlock _NSConcreteMallocBlock _NSConcreteGlobalBlock

另外還包括只在GC環境下使用的 _NSConcreteFinalizingBlock _NSConcreteAutoBlock _NSConcreteWeakBlockVariable

下面摘自 libclosure-65 – Block_private.h-213

_NSConcreteGlobalBlock & _NSConcreteStackBlock

_NSConcreteGlobalBlock & _NSConcreteStackBlock 是 block 初始化時設定的型別(上文中 Block-ABI-Apple 已經提及,並且 CGBlocks_8cpp_source.html#l00141 也提到過)。

在以下情況中,block 會初始化為 _NSConcreteGlobalBlock

_NSConcreteMallocBlock

在非垃圾收集環境下,當 _NSConcreteStackBlock 型別的block 被真正複製時,在 _Block_copy_internal 方法內部,會轉換為 _NSConcreteMallocBlock libclosure-65/runtime.c

_NSConcreteFinalizingBlock&_NSConcreteAutoBlock

在垃圾收集環境下,當 block 被複制時,如果block 有 ctors & dtors 時,則會轉換為 _NSConcreteFinalizingBlock 型別,反之,則會轉換為 _NSConcreteAutoBlock 型別

_NSConcreteWeakBlockVariable

GC環境下,當物件被 __weak __block 修飾,且從棧複製到堆時,block 會被標記為 _NSConcreteWeakBlockVariable 型別。

ARC環境的特殊處理

下面的程式碼均通過新增 objc_retainBlock _Block_copy_Block_copy_internal 符號斷點進行測試

  • 在 ARC 下,block 型別通過=進行傳遞時,會導致呼叫objc_retainBlock->_Block_copy->_Block_copy_internal方法鏈。並導致 __NSStackBlock__ 型別的 block 轉換為 __NSMallocBlock__ 型別。


objc4-680/runtime/NSObject.mm-193
提及到了這一點。

測試程式碼:

日誌:

  • 在 ARC 下,不同的屬性修飾符以及不同賦值、取值方式均會對方法呼叫產生影響。下表為測試結果。
\ STRONG RETAIN COPY
直接賦值 _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal
間接賦值 _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal
通過屬性取值 _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal
通過變數取值

直接賦值:

間接賦值:

通過屬性取值

通過變數取值

測試程式碼:

日誌:

相關文章