眾所周知,當(dāng)某個(gè)對象持有著一個(gè)Block的時(shí)候,如果在Block內(nèi)部使用強(qiáng)引用反過來持有這個(gè)對象,就會(huì)導(dǎo)致引用循環(huán)。為了避免引用循環(huán),可以使用__weak修飾符,蘋果的官方文檔在用代碼演示__weak修飾符的時(shí)候,有這么一個(gè)例子:

那么,myController持有著completionHander,在completionHander內(nèi)部又用一個(gè)strongMyController反過來去持有myController,這不也是一個(gè)引用循環(huán)嗎?為了探究這個(gè)問題,可以用下面的方法來測試一下:
1、編寫一個(gè)類ViewController,然后在類內(nèi)編寫方法test,做一個(gè)疑似的引用循環(huán):

2、然后通過一個(gè)clang命令將這個(gè)類轉(zhuǎn)換成C語言代碼:
clang -x objective-c -rewrite-objc -isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk
-fobjc-arc -stdlib=libc++ -mmacosx-version-min=10.7 -fobjc-runtime=macosx-10.7
-Wno-deprecated-declarations ViewController.m
3、由此可以得到一個(gè)cpp文件,將文件中主要的部分提取出來如下:

4、可以發(fā)現(xiàn):
- 在Block結(jié)構(gòu)體中看到,被Block捕獲的變量是
ViewController *const __weak weakSelf;
所以Block本身對self的引用仍然只是弱引用,并不造成引用循環(huán)。
- strongSelf只存在于Block對應(yīng)的函數(shù)__ViewController__test_block_func_0里,它的生命周期只在這個(gè)函數(shù)執(zhí)行的過程中,函數(shù)執(zhí)行前它不會(huì)存在,函數(shù)執(zhí)行完它立刻就被釋放了。
- 所以:
①、如果函數(shù)執(zhí)行前self變?yōu)閚il了,那么函數(shù)不會(huì)執(zhí)行,沒有任何引用循環(huán)發(fā)生;
②、如果函數(shù)執(zhí)行過程中self變?yōu)閚il了,那么函數(shù)一開始聲明的strongSelf會(huì)暫時(shí)持有著self,此時(shí)會(huì)有一個(gè)暫時(shí)的引用循環(huán)。當(dāng)函數(shù)執(zhí)行完(即是Block執(zhí)行完),strongSelf超出作用域被釋放,引用循環(huán)從這里開始打破。接下來,由于沒有任何強(qiáng)引用持有self了,于是self被釋放,最后Block也因?yàn)闆]有任何強(qiáng)引用持有它也被釋放了。所有對象就都被順利釋放了。
所以最終可以確定:蘋果的演示代碼有可能會(huì)造成引用循環(huán),但是只是一個(gè)暫時(shí)的、可以被打破的引用循環(huán),不會(huì)導(dǎo)致內(nèi)存泄漏。