今天在開(kāi)發(fā)過(guò)程中坟乾,發(fā)現(xiàn)某個(gè)類里的通知(NSNotificationCenter)有時(shí)會(huì)被執(zhí)行好幾次。通知的使用是在viewDidLoad方法里注冊(cè)蝶防,在dealloc方法中移除甚侣。按理來(lái)說(shuō),在viewcontroller的生命周期里這兩個(gè)方法都只會(huì)執(zhí)行一次间学,是相對(duì)應(yīng)的殷费,所以不應(yīng)該存在通知被執(zhí)行多次的情況。在排查后發(fā)現(xiàn)了原因:這個(gè)頁(yè)面在被pop移出棧后沒(méi)有被釋放(即沒(méi)有走dealloc方法)低葫。
百度了pop移出棧后沒(méi)有被釋放的原因详羡,歸根結(jié)底,是因?yàn)楫?dāng)前控制器被某個(gè)對(duì)象強(qiáng)引用了氮采,控制器的引用計(jì)數(shù)不為0殷绍,系統(tǒng)無(wú)法幫你釋放這部分內(nèi)存。大致分為以下幾種情況
1.控制器中NSTimer沒(méi)有被銷毀
2.viewController中的代理不是weak屬性
3.viewController中block的循環(huán)引用
對(duì)照以上情況和工程實(shí)際情況鹊漠,前兩種那個(gè)頁(yè)面沒(méi)有使用到主到,所以開(kāi)始排查第三種情況。最終發(fā)現(xiàn)是解除循環(huán)引用用的是__block修飾躯概,所以導(dǎo)致了pop后頁(yè)面無(wú)法釋放登钥。
__block本身并不能避免循環(huán)引用,避免循環(huán)引用需要在block內(nèi)部把__block修飾的obj置為nil
__weak可以避免循環(huán)引用娶靡,但是其會(huì)導(dǎo)致外部對(duì)象釋放了之后牧牢,block 內(nèi)部也訪問(wèn)不到這個(gè)對(duì)象的問(wèn)題,我們可以通過(guò)在 block 內(nèi)部聲明一個(gè) __strong的變量來(lái)指向 weakObj姿锭,使外部對(duì)象既能在 block 內(nèi)部保持住塔鳍,又能避免循環(huán)引用的問(wèn)題
__block和__weak修飾符的區(qū)別:
1.__block對(duì)象可以在block中被重新賦值,__weak不可以呻此。
2._block會(huì)持有該對(duì)象轮纫,即使超出了該對(duì)象的作用域,該對(duì)象還是會(huì)存在的焚鲜,直到block對(duì)象從堆上銷毀掌唾;而__weak僅僅是將該對(duì)象賦值給weak對(duì)象,當(dāng)該對(duì)象銷毀時(shí)忿磅,weak對(duì)象將指向nil糯彬;
3.__block不管是ARC還是MRC模式下都可以使用,可以修飾對(duì)象葱她,還可以修飾基本數(shù)據(jù)類型撩扒。
4.__weak只能在ARC模式下使用,也只能修飾對(duì)象吨些,不能修飾基本數(shù)據(jù)類型搓谆。
5.__block對(duì)象在ARC下可能會(huì)導(dǎo)致循環(huán)引用,非ARC下會(huì)避免循環(huán)引用锤灿,__weak只在ARC下使用挽拔,可以避免循環(huán)引用。
如果block沒(méi)有直接或者間接被self存儲(chǔ)但校,就不會(huì)產(chǎn)生循環(huán)引用螃诅,就不需要用weak self。在block里有時(shí)直接用self之類的強(qiáng)引用對(duì)象時(shí)状囱,而系統(tǒng)沒(méi)有警告术裸,這不代表不會(huì)造成對(duì)象無(wú)法釋放的情況。
只要你在block里用到了self所擁有的東西亭枷,都有可能造成循環(huán)引用袭艺,一定要注意!_墩场;唷A龆谩!4鸪轰传!