最近在看SDWebImage源碼,碰到一些比較繞的問題,理解了很久,然後在網上查了些的資料,才算是有了一些理解。在此記錄一下。 源碼如下: block會copy要在block中使用的實變數,而copy會是變數的retainCount + 1,如若在不註意很容易造成迴圈引用。而所謂的迴圈引用的本質就是 ...
最近在看SDWebImage源碼,碰到一些比較繞的問題,理解了很久,然後在網上查了些的資料,才算是有了一些理解。在此記錄一下。
源碼如下:
block會copy要在block中使用的實變數,而copy會是變數的retainCount + 1,如若在不註意很容易造成迴圈引用。而所謂的迴圈引用的本質就是,兩個對象相互引用,從而造成對象不能正常的dealloc。所以解決的辦法就是讓引用的一方是weak的,這樣就使得相互引用的閉環被打破,能夠正常的dealloc了。
1)weakSelf的使用:
Apple 官方的建議是,傳進 Block 之前,把 ‘self’ 轉換成 weak automatic 的變數,這樣在 Block 中就不會出現對 self 的強引用。
上圖的代碼中,backgroundTaskId是當前這個類的一個屬性,在backgroundTaskId初始化的這個方法中,有一個block回調,在這個block的實現中訪問需要訪問Self,為了避免造成迴圈引用,此處給當前的Self取了個別名,並用__weak來修飾,目的是告訴編譯器,此處是弱引用,不要retain 當前的這個類,也就是所謂的self。
2)為什麼會出現strongSelf?
Apple 官方文檔有講到,如果在 Block 執行完成之前,self 被釋放了,weakSelf 也會變為 nil。
clang給出的實例代碼:
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomething];
});
clang 的文檔表示,在 doSomething 內,weakSelf 不會被釋放。但,下麵的情況除外:
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomething];
[weakSelf doOtherThing];
});
在 doSomething 中,weakSelf 不會變成 nil,不過在 doSomething 執行完成,調用第二個方法 doOtherThing 的時候,weakSelf 有可能被釋放,
於是,strongSelf 就派上用場了:
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong __typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doOtherThing];
});
__strong 確保strongSelf在block中不會被釋放。
所以就能理解SDWebImage中的那段代碼,block在實現的過程中會對wself進行一次強引用,是為了防止在block還未執行完畢,wself在其他線程中被釋放,使得wself為nil。
簡單的做個小結:
1、在使用block時,如果block內部需要訪問self的方法、屬性、或者實例變數應當使用weakSelf
2、如果在block內需要多次訪問self,則需要使用strongSelf
3、如果在block內部存在多線程環境訪問self,則需要使用strongSelf
4、block本身不存在多線程之分,block執行是否是多線程,取決於當前的持有者是否是以多線程的方式來調用它。
clang的文檔鏈接
https://github.com/CoderBeta/clang-user-manual
http://blog.csdn.net/bbmb_mb/article/details/50470802