CAAnimation 中可能意想不到的內(nèi)存泄漏問(wèn)題

先說(shuō)我遇到的此問(wèn)題的場(chǎng)景

示例

如圖,現(xiàn)在這種客戶端跳網(wǎng)頁(yè),上方會(huì)有個(gè)加載進(jìn)度條樣式已經(jīng)很普遍了.市面上幾乎所有的app都是這個(gè)樣式了.

  • 可就在我某次無(wú)聊把玩項(xiàng)目打發(fā)時(shí)間時(shí),偶然發(fā)現(xiàn)此ViewController會(huì)概率發(fā)生pop到上級(jí)頁(yè)面后不釋放問(wèn)題,沒(méi)有走dealloc方法 -_-!!!
  • 內(nèi)存泄漏可是項(xiàng)目大忌啊,好怕怕 *_*.發(fā)現(xiàn)了問(wèn)題就得改啊.

經(jīng)過(guò)多次測(cè)試把玩發(fā)現(xiàn)終于找到重現(xiàn)規(guī)律:
1. 就是在跳轉(zhuǎn)H5頁(yè)面后
2. 在webView還未完全加載完成,上方動(dòng)畫條progress還未走到100%時(shí)
3. 返回到上級(jí)頁(yè)面后,該ViewController就會(huì)出現(xiàn)內(nèi)存泄漏的問(wèn)題

  • 我的bug修復(fù)之旅:
  1. 起初我以為是webView的問(wèn)題,折騰了很長(zhǎng)時(shí)間發(fā)現(xiàn)無(wú)果.結(jié)果是webView最終釋放了,但是控制器仍然沒(méi)有釋放.(當(dāng)然webView使用不當(dāng),也會(huì)造成內(nèi)存泄漏,這不是本次的討論重點(diǎn))
  2. 于是,我把思路轉(zhuǎn)向第二個(gè)必現(xiàn)條件progress動(dòng)畫上.可是動(dòng)畫那一塊的代碼看去看來(lái)也不覺(jué)得有問(wèn)題啊.
  3. 最后我猜可能是block使用不當(dāng),也許是哪一塊出現(xiàn)了循環(huán)引用導(dǎo)致的.最后結(jié)果是,大把的時(shí)光飛去,那個(gè)背鍋的block代碼塊并沒(méi)有被我找到.
  4. 就在我一籌莫展之際,突然靈光一閃,我之所以懷疑block的更本原因是循環(huán)引用.那此控制器不被釋放定然也是被什么給強(qiáng)引用了一下,pop到上級(jí)頁(yè)面的時(shí)候,它沒(méi)有釋放,導(dǎo)致了當(dāng)前頁(yè)面也沒(méi)有釋放.于是我又把目光投向了第二步
  5. 只有動(dòng)畫未完成時(shí),才會(huì)內(nèi)存泄漏,那就應(yīng)該是animation對(duì)象強(qiáng)行持有了當(dāng)前控制器.再次查看代碼:
    animation.duration = duration;
    animation.autoreverses = NO;
    animation.toValue = [NSValue valueWithCGRect:frame];
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.delegate = self;
    [self.progressView.layer addAnimation:animation forKey:@"progress"];

這里唯一一處引用了當(dāng)前控制器的代碼animation.delegate = self;于是我點(diǎn)開delegate進(jìn)入看了下

@property(nullable, strong) id <CAAnimationDelegate> delegate;

額!!! 官方給出此屬性定義的是strong類型,我們平時(shí)在開發(fā)時(shí),為了防止內(nèi)存泄漏,都定義的是weak或者assign.但是這里給出的是strong.也難怪我第一次看到這段代碼的時(shí)候直接就忽略掉它了.坑呀

  • 找到了原因,問(wèn)題就好解決了.我在控制器生命周期中某個(gè)適當(dāng)?shù)沫h(huán)節(jié)添加了這句代碼
[self.progressView.layer removeAllAnimations];

這樣就ok了,記得適當(dāng)時(shí)機(jī)移除掉動(dòng)畫.animation釋放了,self自然就不再被持有了.

  • 但是出于好奇為何animation的delegate用的是strong來(lái)定義,之前一直沒(méi)注意.最后查閱了相關(guān)資料才有所了解
  • 首先動(dòng)畫是異步的,在動(dòng)畫的過(guò)程中,它的 delegate 隨時(shí)都有可能被釋放掉,如果不是個(gè)強(qiáng)引用的話,比如用戶點(diǎn)了返回之類的。另外一方面,一般來(lái)說(shuō)你并不會(huì)持有一個(gè) CAAnimation 的強(qiáng)引用(跟 UITableView 不一樣)。文檔里也說(shuō)這是內(nèi)存管理規(guī)則中的一個(gè)例外。

自己遇到的問(wèn)題,拿出來(lái)總結(jié)一下.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容