block裡的self、weakSelf、strongSelf
阿新 • • 發佈:2018-11-09
ARC下,關於block裡面使用self、weakSelf、strongSelf,理解一直沒有特別的透徹,今天花時間研究了一下,總結如下:
其實一共就涉及到兩個問題:
1.是否迴圈引用了
2.block裡面的程式碼,不一定執行到哪行時,VC可能就釋放了,self就為nil了,那麼你到底想讓程式碼在這種情況下如何執行。
其實到底用self、weakSelf還是strongSelf,就是上面兩個問題的排列組合
有種典型的寫法:
1.不成環,並且想讓block程式碼什麼情況下都執行:兩種方式:A全部使用self就行;B外面定義weak,block裡面用strong,也行,多次一舉。
2.不成環,並且想讓block程式碼在當前VC釋放的情況下不執行:兩種方式:A外面定義weak,裡面使用weak,然後注意nil可能會crash的地方(加判斷);B外面定義weak,block裡面使用strong(或者直接使用self),自己加if判斷,否是在當前頁面,不在當前頁面不執行。
3.成環,想讓block程式碼無論如何都執行:必用weak。block裡面用strong。
4.成環,想讓block程式碼在當前VC釋放的情況下不執行:兩種方式:A必用weak,block裡面用strong,則自己加if判斷不在當前頁面就不執行;B,block裡面使用weak,注意nil可能導致crash的地方。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); __weak __typeof__(self) weakSelf = self; dispatch_async(queue, ^{ __typeof__(self) strongSelf = weakSelf; [strongSelf assitFunc1]; });
首先我的結論是,所有情況下,這麼寫是不會出什麼問題的(當然也好多情況下不用這麼寫),唯一可能出問題的地方就是要保證block裡面的程式碼能夠被執行到,否則就和迴圈引用一樣,是不會釋放VC的。什麼情況會執行不到?比如queue裡面已經有1萬個任務,然後正在序列執行,當然這裡說的是理論上,所以一般也不會有這種情況。 不會出問題的原因是:不會造成迴圈引用,因為沒有對self持有(其實是block程式碼期間持有了,執行完畢就不持有了);block裡的程式碼一定會執行,因為strongSelf會保證在block程式碼執行完畢之前self不會被釋放(延遲了VC的生命週期),並且執行的時候strongSelf一定不會為nil。所以沒有問題。 然後說下weak和strong的作用: 1.weakSelf,不增加self的引用計數,然後你還可以使用它,所以它能防止迴圈引用(該釋放釋放,和weakSelf怎麼用完全沒關係)。 2.strongSelf,在定義的區域內保證指向的內容不被釋放,所以他用在確保程式碼執行的時候。(防止self變成nil,延遲self的生命)。 到底怎麼用有以下情況: 1.不管使用self,還是strongSelf,都延遲了VC釋放的時間,至少要執行完block。 2.如果block是臨時的block,例如在ViewDidLoad裡面寫上面的程式碼。直接使用self就可以達到同樣的效果,不會出現記憶體洩露,因為雖然block持有self,但是self並沒有持有block,沒有成環。並且注意,self一定會晚於或者等於block執行完畢的時間釋放。就算執行到block中的某行程式碼,並不在當前VC了,也不會crash,因為self沒有釋放。 所以好多時候,如果block和self沒有成環,我們就直接使用self就行了。無需定義weakSelf和strongSelf。但是有時候沒有成環,我們依然使用了weakSelf,這時其實可以達到這樣的效果:如果VC釋放了(不在當前頁了),那麼由weakSelf方法呼叫的函式,其實都不執行了,就達到了節省資源的目的,需要注意的是對於nil的處理,避免crash。既用weak又用strong就沒必要了,就和直接使用self時一個效果。 3.如果成環了,那麼一定會使用weak。至於block裡面的程式碼是全部使用weak還是全部使用strong,就取決於當self變成nil時,你想讓程式碼如何執行,如果無論如何你都想執行block裡面的程式碼,那麼就用strong,如果想要self為nil時,不執行一些程式碼,則凡是使用weakSelf的函式都不會被執行,也必須注意可能會crash的地方。 結論: