天天看點

ARC中block塊作為屬性的使用筆記

arc中block塊作為屬性的使用筆記

ARC中block塊作為屬性的使用筆記

block較難了解,根據在記憶體中的分布情況就分為3種類型,根據使用的情形又分為很多很多種。雖然用起來容易,但使用不當會造成記憶體洩露,雖然都是這麼說,但你真的研究過為什麼會洩露嗎?為什麼有些時候外部變量進入block的時候會導緻引用計數+1呢?

本人做過mrc以及arc的開發,但大勢所趨,arc将是以後開發的主要模式,即使有mrc也是arc混編mrc的代碼,是以,本文的block的一些使用上的心得都基于arc的,已經不考慮mrc的了,請看官注意,mrc與arc的block是有着很多很多差別的。

注意,以下心得是我自己長時間收集資料以及自己驗證所的出來的一些技巧與結論,不代表它的正确性,這僅僅是筆記,取舍由你決定,最好自己驗證一下。

首先建立出如下形式的工程,cv1 push 到cv2的這種形式。

ARC中block塊作為屬性的使用筆記

它們的強引用關系如下:

ARC中block塊作為屬性的使用筆記

以下是cv2的代碼,注意,要将block定義成copy屬性。

ARC中block塊作為屬性的使用筆記

block被copy了有着什麼現象發生呢?引用一段原文。

blocks are similar to other objects for memory management, but

not the same. when a block which accesses local variables is created, it

is created on the stack. this means that it is only valid as long as its

scope exists. to save this block for later, you must copy it, which copies

it to the heap.

blocks與其他對象的記憶體管理相似,但又有着不同。當一個block(block當中有着外部變量進入)被建立了,它是在堆區中的。那意味着,當block中的代碼執行完畢之後,這段代碼就再也不合法了,會被清除掉。為了讓這個block存活時間更久。你必須copy,将它拷貝到棧區。

1. cv1 push 到cv2,cv2在棧區裡面,cv2 pop 掉後整個控制器都被釋放。

2. 作為屬性的block被copy之後會出現在cv2棧區裡面,為什麼在棧區裡面,很簡單,它要随着cv2的生命周期一緻,cv2 pop

掉後這個block也會跟着一起消失的。

他們的強引用關系如下圖所示:

ARC中block塊作為屬性的使用筆記

以下情形叫做有外部變量進入block的情形,其中的self.name就是控制器cv2的一個屬性,對于block來講屬于外部變量。

ARC中block塊作為屬性的使用筆記

這裡有一個問題,對于進入到block裡面的外部變量,為什麼會被block強引用呢?

我們可以這麼想,block塊中的代碼并不是馬上就會執行的,需要你手動調用才行,如上例中的self.oneblock(@“youxianming”);有時候,這個方法都執行結束了,這個block還沒有執行,如果block中的對象沒有被block強引用,很有可能那個變量已經消失了卻還調用了block,直接後果就是崩潰。為了保證block至少能用上一次,它必須強引用進入到裡面的外部變量。

是以上圖中的強引用關系圖如下所示:

ARC中block塊作為屬性的使用筆記

如果cv2 pop 了,其釋放過程是這樣子的:

ARC中block塊作為屬性的使用筆記

cv2被cv1強引用消失,cv2就會挨個檢查強引用,如果沒有發現自己被什麼強引用,就會把所有的内容清除掉,就是上圖中的oneblock以及name。

最後,之後輪到oneblock了,它也會解除name的強引用關系:

ARC中block塊作為屬性的使用筆記

至此,都是很完美的,沒有記憶體洩露什麼的。

我們把代碼修改成如下的形式,我們在block中執行一個方法,讓控制器執行一個方法,即[self ......];

ARC中block塊作為屬性的使用筆記

它們的強引用關系圖如下,注意下圖中的藍色的線條,因為外部變量self(cv2自身)傳了進來,隻出現的self也算傳進來了哦。

ARC中block塊作為屬性的使用筆記

這個時候,你如果将 cv2 pop掉。它們的關系圖如下所示:

ARC中block塊作為屬性的使用筆記

這個時候,cv2會檢測自己有沒有被強引用,結果發現被一個對象oneblock強引用了,那麼它自身就不會被釋放掉,整個cv2都洩露了呢,洩露的原因就是循環引用。

這時候,你再從cv1 push 出cv2,以下是關系圖:

ARC中block塊作為屬性的使用筆記

再次pop又會洩露一個cv2。每次的push與pop都會導緻一個新的cv2整體被洩露哦。

這還隻是作為屬性的block。其他的還沒講呢。作為屬性的block是最容易出現循環引用事件的。block的知識都比較隐晦,你以為你懂了,其實你沒懂。需要抱着一顆不浮躁的心,慢慢的分析它的特性,寫代碼驗證自己的想法,然後才會使用得得心應手。