最近在看 AFNetworking 和 SDWebImage源碼,碰到一些比較繞的問題,理解了好久,而後在網上查了些的資料,纔算是有了一些理解。在此記錄一下。git
AFNetworking 源碼以下:github
SDWebImage 源碼以下:多線程
block會copy要在block中使用的實變量,而copy會是變量的retainCount + 1,如若在不注意很容易形成循環引用。async
而所謂的循環引用的本質就是,兩個對象相互引用,從而形成對象不能正常的dealloc。spa
因此解決的辦法就是讓引用的一方是weak的,這樣就使得相互引用的閉環被打破,可以正常的dealloc了。.net
1)weakSelf的使用:線程
Apple 官方的建議是,傳進 Block 以前,把 ‘self’ 轉換成 weak automatic 的變量,這樣在 Block 中就不會出現對 self 的強引用。 3d
上圖的代碼中,backgroundTaskId是當前這個類的一個屬性,在backgroundTaskId初始化的這個方法中,有一個block回調,在這個block的實現中訪問須要訪問Self,爲了不形成循環引用,此處給當前的Self取了個別名,並用__weak來修飾,目的是告訴編譯器,此處是弱引用,不要retain 當前的這個類,也就是所謂的self。code
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。
簡單的作個小結:
一、在使用block時,若是block內部須要訪問self的方法、屬性、或者實例變量應當使用weakSelf
二、若是在block內須要屢次訪問self,則須要使用strongSelf
三、若是在block內部存在多線程環境訪問self,則須要使用strongSelf
四、block自己不存在多線程之分,block執行是不是多線程,取決於當前的持有者是不是以多線程的方式來調用它。
clang的文檔連接
https://github.com/CoderBeta/clang-user-manual
http://blog.csdn.net/bbmb_mb/article/details/50470802