(轉自https://github.com/oa414/objc-zen-book-cn 禪與 Objective-C 編程藝術 )
一些關鍵點:
block 是在棧上創(chuàng)建的
block 可以復制到堆上
Block會捕獲棧上的變量(或指針),將其復制為自己私有的const(變量)。
(如果在Block中修改Block塊外的)棧上的變量和指針,那么這些變量和指針必須用__block
關鍵字申明(譯者注:否則就會跟上面的情況一樣只是捕獲他們的瞬時值)。
如果 block 沒有在其他地方被保持,那么它會隨著棧生存并且當棧幀(stack frame)返回的時候消失。僅存在于棧上時,block對對象訪問的內存管理和生命周期沒有任何影響。
如果 block 需要在棧幀返回的時候存在,它們需要明確地被復制到堆上,這樣,block 會像其他 Cocoa 對象一樣增加引用計數(shù)。當它們被復制的時候,它會帶著它們的捕獲作用域一起,retain 他們所有引用的對象。
如果一個 block引用了一個棧變量或指針,那么這個block初始化的時候會擁有這個變量或指針的const副本,所以(被捕獲之后再在棧中改變這個變量或指針的值)是不起作用的。(譯者注:所以這時候我們在block中對這種變量進行賦值會編譯報錯:Variable is not assignable(missing __block type specifier)
,因為他們是副本而且是const的.具體見下面的例程)。
當一個 block 被復制后,__block
聲明的棧變量的引用被復制到了堆里,復制完成之后,無論是棧上的block還是剛剛產生在堆上的block(棧上block的副本)都會引用該變量在堆上的副本。
聲明的變量和指針在 block 里面是作為顯示操作真實值/對象的結構來對待的。
block 在 Objective-C 的 runtime(運行時) 里面被當作一等公民對待:他們有一個 isa
指針,一個類也是用 isa
指針在Objective-C 運行時來訪問方法和存儲數(shù)據(jù)的。在非 ARC 環(huán)境肯定會把它搞得很糟糕,并且懸掛指針會導致 crash。__block
僅僅對 block 內的變量起作用,它只是簡單地告訴 block:
嗨,這個指針或者原始的類型依賴它們在的棧。請用一個棧上的新變量來引用它。我是說,請對它進行雙重解引用,不要 retain 它。 謝謝,哥們。
如果在定義之后但是 block 沒有被調用前,對象被釋放了,那么 block 的執(zhí)行會導致 crash。 __block
變量不會在 block 中被持有,最后... 指針、引用、解引用以及引用計數(shù)變得一團糟