一李请、問題描述
ViewController不釋放藤抡,會(huì)導(dǎo)致很多問題辫封,我舉幾個(gè)我遇到的例子硝枉。
- 我做的是一個(gè)企業(yè)即時(shí)通訊APP,我做了一個(gè)群公告功能倦微,發(fā)布群公告時(shí)會(huì)發(fā)送@all消息妻味。某天,我做完了群公告欣福,發(fā)了一個(gè)群公告試試责球,結(jié)果,消息群發(fā)了拓劝,發(fā)到了好幾個(gè)聊天會(huì)話中去了雏逾。因?yàn)閏hattingViewController沒有釋放掉,發(fā)送@all消息的通知郑临,那些沒有被釋放掉的chattingViewController都收到了栖博,都執(zhí)行了發(fā)送@all消息的動(dòng)作,所以導(dǎo)致很多會(huì)話都發(fā)送了@all消息厢洞。
- 我做一個(gè)踢出登錄的功能笛匙,退到登錄頁(yè)面的時(shí)候,之前的主界面都沒有被釋放犀变,踢出登錄會(huì)發(fā)一個(gè)通知妹孙,顯示一個(gè)alert:你被踢出登錄。多次被踢出获枝,就會(huì)創(chuàng)建多個(gè)主界面蠢正,多個(gè)主界面都會(huì)收到這個(gè)通知,于是就顯示了多個(gè)alertView省店。
- NSTimer嚣崭,NSTimer會(huì)對(duì)它的target持有強(qiáng)引用,如果NSTimer不釋放掉懦傍,就會(huì)一直持有它的target的強(qiáng)引用雹舀,會(huì)一直都釋放不掉,造成內(nèi)存泄露粗俱。
二说榆、解決方法
怎么知道ViewController有沒有被釋放,有一個(gè)方法就是可以通過看ViewController有沒有執(zhí)行dealloc方法。
大概有幾個(gè)地方签财,比較容易引起內(nèi)存泄露
-
循環(huán)引用串慰;最多的就是block引起的循環(huán)引用。
(1)某個(gè)類將block作為自己的屬性變量唱蒸,然后該類在block的方法體里面又使用了該類本身;相互持有邦鲫,導(dǎo)致都釋放不了。代碼例子: [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view); make.top.equalTo(self.navigationBar.mas_bottom); make.bottom.equalTo(self.view); }]; 修改為: __weak typeof(self) weakSelf = self; 塊內(nèi)的self神汹,換成weakSelf就行了庆捺。 block不是self的屬性或者變量時(shí),在block內(nèi)使用self不會(huì)循環(huán)引用; (2)如果塊是一個(gè)單例持有的屁魏,塊內(nèi)又使用了ViewController這個(gè)類滔以,會(huì)引起循環(huán)引用。 例子: [[OutsidePacketsSchedule shareInstance] sendParameters:dict requestCmd:@"addCustomEmoReq" responseCmd:@"addCustomEmoRsp" complete:^(id response, NSError *error) { if(!error){ [weakSelf.view setToast:@"添加自定義表情成功"]; } }]; 上例中的單例持有的代碼塊中要用弱引用蚁堤,原因是:?jiǎn)卫粫?huì)被釋放掉,它會(huì)一直持有block但狭,導(dǎo)致該block所在的ViewController釋放不掉披诗。 (3)如果是方法中的參數(shù)是block,不會(huì)造成循環(huán)引用立磁,因?yàn)榉椒ㄖ械腷lock是位于棧內(nèi)存的呈队,方法返回后,block將會(huì)無效唱歧。
-
NSTimer和CADisplayLink這種宪摧;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(nullable id)userInfo
repeats:(BOOL)yesOrN{} 從文檔中方法的定義上可以看到,NSTimer是會(huì)強(qiáng)引用它的target的颅崩,像其他的delegate一般都是weak的几于,所以這里比較特殊。 NSTimer Class Reference是這樣對(duì)target描述的: The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated. NSTimer Class Reference還指出: Runloop會(huì)強(qiáng)引用timer沿后,因?yàn)槿绻粋€(gè)timer是循環(huán)的沿彭,如果沒被強(qiáng)引用,那么在函數(shù)返回后尖滚,則會(huì)被銷毀喉刘,就不能循環(huán)地通知持有的target。所以NSTimer是被放到Runloop中執(zhí)行的漆弄。 如果我們不調(diào)用invalidate timer,runloop就會(huì)一直持有timer,而timer也一直持有ViewController睦裳,這樣就會(huì)造成內(nèi)存泄露。 解決這類問題的方法就是:在不需要NSTimer的時(shí)候撼唾,及時(shí)調(diào)用[self.timer invalidate]廉邑。千萬不要在dealloc方法中調(diào)用,因?yàn)镹STimer強(qiáng)引用self,所以不會(huì)執(zhí)行dealloc方法鬓催。
delegate一般是weak的情況分析肺素;
這里我遇到的情況,在我的第一篇博客里面有寫到宇驾,感興趣的可以去看一下倍靡。對(duì)象之間的循環(huán)引用:例子:兩個(gè)ViewController都需要使用對(duì)方,這個(gè)時(shí)候可以用@class
是我解決ViewController不釋放的時(shí)候遇到的一個(gè)個(gè)例問題课舍,當(dāng)時(shí)把ViewController里的每行代碼都分析了塌西,強(qiáng)引用的地方都解決了,還是不執(zhí)行dealloc方法筝尾,查了好久捡需,請(qǐng)教了好幾個(gè)同事,最后筹淫,發(fā)現(xiàn)站辉,竟然是這個(gè)ViewController沒有開啟ARC,不知道是被那個(gè)隊(duì)友給關(guān)閉了损姜,哭瞎=饰剥。=
三、最后的建議
上文中我主要是根據(jù)自己在項(xiàng)目中遇到的問題摧阅,及如何解決的汰蓉,來描述的。不是很詳細(xì)深入棒卷,這里建議多看一下官方文檔顾孽,一般的問題都可以通過閱讀官方文檔來解決的。