編寫高質量代碼的52個方法

NO

第六章 塊與大中樞派發(GCD)

37. 塊的基本概念
  • 塊的強大之處:在聲明它的范圍里所有變量都可以為其所捕獲. 默認情況下,為塊所捕獲的變量,是不可以在塊里修改的.若聲明變量的時候加上__block修飾符,就可以在塊內修改了.
  • 塊可以分配在棧或堆上,?也可以是全局的.分配在棧上的塊可以copy到堆上,一旦拷貝到堆上,塊就成了帶引用計數的對象了.后續的復制都不會真的執行復制,只是遞增塊對象的引用計數
  • 全局塊:不會捕捉任何狀態,運行時也無須有狀態來參與.塊所使用的整個內存在編譯期就已經完全確定了.屬于一種優化操作
  void (^block)() = ^{
   NSLog(@"全局塊");
};
  • 如果將塊定義在實例方法中,那么除了可以訪問類的所有實例變量外,還可以使用self變量.塊總能修改實例變量,所以在聲明時無需添加__block.不過如果通過讀取或寫入操作捕獲了實例變量,那么也會自動將self變量一并捕獲,因為實例變量是與self所指代的實例關聯在一起的.
  • self也是個對象,因而塊在捕獲它時,也會將其保留,如果self所指代的對象同時也保留了塊,那么會導致保留環.
塊的內部結構
  • 塊的內存布局:塊本身也是個對象,在存放的內存區域中,首個變量是指向Class對象的指針.其余內存里含有塊對象正常運轉所需的各種信息


    塊的內部結構.png
  • 在內存布局中,最重要的就是invoke變量,這是個函數指針,指向塊的實現代碼.函數原型至少要接受一個void* 型的參數,此參數代表塊. 塊其實就是一種代替函數指針的語法結構,原來使用函數指針時,需要用"不透明的void指針"來傳遞狀態,而改用塊后則可以把原來用C語言所編寫的代碼封裝成簡明易用的接口.
  • descriptor變量是指向結構體的指針,每個塊里都包含此結構體,其中聲明了塊對象的總體大小,還聲明了copy和dispose兩個輔助函數所對應的函數指針.輔助函數在拷貝及丟棄塊對象是運行,比如copy要保留捕獲的對象,dispose則將之釋放.
  • 塊還會把它所捕獲的所有變量都拷貝一份.這些拷貝放在descriptor變量后面,捕獲多少個變量,就要占據多少內存空間.請注意拷貝的不是對象本身,而是指向這些對象的指針變量.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容