淺談OC中的迴圈引用問題
將近一個月沒有寫文章了,藉口就不一一羅列了。。。。
廢話不多說,進入正題。
談到迴圈引用這個問題,相信很多iOS的童鞋至少都在運用block技術的時候遇到過,同樣的,很多童鞋肯定也是通過weak這個關鍵字來處理的,但是我相信,這其中肯定有不少童鞋並沒有搞明白為什麼會發生迴圈引用。本篇短文章,就以自己的理解與總結,淺談一下OC中的迴圈引用。
首先,來看一下什麼是迴圈引用。這裡,以一個小例子來簡述:
有兩個類:Man與Woman,Man中有一個Woman屬性,而Woman中又有一個Man屬性,專業簡潔一點的說法,也就是Man與Woman相互引用,此時,咱們在控制器的viewDidLoad方法中建立Man物件man與Woman物件woman,然後再執行這兩個物件的release方法,此時,對於viewDidLoad方法來說,已經釋放了自己對於man和woman這兩個物件的持有權,但是,此時man與woman的引用計數不是0,而是1,因為它們互相引用了。這就從而導致man與woman這兩個物件永遠無法釋放,從而就造成了記憶體洩露的現象。
上面這個簡單的小例子,就是迴圈引用的呈現,可能對於有些只在block中遇到迴圈引用問題的童鞋來說,還理解不了:難道block中的迴圈引用就是因為這個????
下面,咱們就來總結一下,迴圈引用這個現象會在哪些情形下出現。
一、運用NSTimer時。
(可能很多童鞋都跟我一樣,接觸NSTimer要比接觸block早一點點。)
運用NSTimer時,必然少不了target這個概念(通常情況下,這個target就是self),而NSTimer預設會對target有強引用,因此,如果在target(self)釋放之前,沒有先釋放或者停止NSTimer,那麼就會出現迴圈引用引起的記憶體洩漏問題了。
歸結於上述原因,因此,在使用NSTimer時,咱們總是在target(self)釋放之前,先呼叫NSTimer的invalidate方法來停止NSTimer(更保險的做法是,在target的dealloc方法中置空NSTimer),如果存在NSTimer的相關執行受外界控制的情形時,則應該向外界提供停止NSTimer的方法,讓外界在釋放target之前,先停止NSTimer。
二、運用block時。
(終於該說block了。。。。)
當block作為屬性變數存在於一個類中時,並且這個類在block的實現程式碼中使用了這個類自身(self),那麼就會出現迴圈引用的現象。對於這種情形,咱們的處理方法就是像本文開頭提到的那樣,在block塊裡面,對這個類進行弱引用(weakSelf)。
三、運用delegate時。
很多童鞋都用過delegate與protocol,那麼為什麼delegate要用weak這個關鍵字來修飾呢?咱們用UITableview來簡單說一下。
tableview的顯示,肯定離不開控制器Controller,因為Controller已經對tableview有一層強引用,此時如果再將delegate設定為strong,那就說明tableview又強引用著Controller(因為Controller是tableview的delegate),這樣,就必然存在迴圈引用了。
因此,在使用protocol及delegate時,通常都是將delegate設定為weak弱引用(MRC下則必須是assign)。
以上,就是對迴圈引用的一些總結,都是樓主在日常工作中的一些認識,或許存在膚淺、甚至錯誤的地方,歡迎各位讀者的各種評論。
PS:部落格園中的iOS開發者是不是很少?怎麼感覺都是java與.net的天下。。。。