問(wèn)題:
當(dāng)前有一個(gè)場(chǎng)景贪庙,當(dāng)WebView接受數(shù)據(jù)的時(shí)候會(huì)觸發(fā)回調(diào),從而觸發(fā)一段特定邏輯当编,該特定邏輯是通過(guò)NSTimer延遲觸發(fā)一段與WebView相關(guān)的代碼箩绍,詳細(xì)請(qǐng)看以下的代碼塊:
... ///<WebView
NSTimer* timer = nil;
TestClass* obj;
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[self.obj testFunction:webView];
}
... ///<TestClass
- (void)timerFunction:(UIWebView*)webView
{
[self cancelTimer]; ///<回收Timer
timer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:@selector(dealWebView:)
userInfo:webView repeats:NO]; ///<通過(guò)WebView創(chuàng)建Timer
}
- (void)cancelTimer
{
[timer invalidate];
[timer release];
timer = nil;
}
- (void)dealWebView:(NSTimer*)sender
{
...
}
分析:
這里存在一個(gè)問(wèn)題,當(dāng)webView發(fā)起第一次DidFinishLoad回調(diào)的時(shí)候梳侨,NSTimer創(chuàng)建后持有了一份WebView計(jì)數(shù)廊移。在沒(méi)有執(zhí)行dealWebView函數(shù)的5秒內(nèi)醒颖,若回收WebView鲤桥,則導(dǎo)致NSTimer持有的WebView成為唯一一份計(jì)數(shù)卑吭。這時(shí)候若又來(lái)了DidFinishLoad,調(diào)用cancelTimer時(shí)丙躏,則會(huì)將WebView析構(gòu)择示,從而導(dǎo)致往下的操作都是非法操作(野指針)。
一般來(lái)說(shuō)這種邏輯結(jié)構(gòu)還是比較容易解決晒旅,但很多業(yè)務(wù)是放在DidFinishLoad這個(gè)回調(diào)的里面的更深函數(shù)堆棧栅盲,則很容易出現(xiàn)這種異步析構(gòu)問(wèn)題。
根本的原因其實(shí)是webview在管理者release前废恋,沒(méi)有通知Timer進(jìn)行析構(gòu)谈秫,導(dǎo)致Timer持有了一份不安全的WebView。(為什么會(huì)是不安全鱼鼓?我們根據(jù)“誰(shuí)創(chuàng)建誰(shuí)析構(gòu)”的原則可以知道拟烫,WebView不是NSTimer創(chuàng)建,但為了確保NSTimer執(zhí)行安全迄本,故需要持有WebView硕淑,而當(dāng)WebView被管理者析構(gòu)的時(shí)候,則該WebView無(wú)論是否被析構(gòu)嘉赎,都將處于無(wú)效狀態(tài)置媳。)
解決:
方案1:在webview中設(shè)置一個(gè)變量,標(biāo)記WebView是否有效曹阔,如果無(wú)效則不處理timerFunction半开。
方案2:將webview析構(gòu)前,通知timer需要主動(dòng)析構(gòu)赃份,回收timer持有的webview計(jì)數(shù),再進(jìn)行析構(gòu)。
討論:
其實(shí)還有很多案例抓韩,如當(dāng)進(jìn)行動(dòng)畫過(guò)程的時(shí)候作用于動(dòng)畫的視圖被管理者析構(gòu)了纠永,動(dòng)畫結(jié)束后的回調(diào)可能需要對(duì)視圖進(jìn)行一些邏輯,但視圖此時(shí)處在不安全狀態(tài)谒拴,很容易產(chǎn)生Crash尝江。關(guān)鍵是當(dāng)管理者析構(gòu)對(duì)象的時(shí)候,是否應(yīng)該通知其他持有這個(gè)對(duì)象的擁有者對(duì)象失效呢英上?
具體問(wèn)題應(yīng)該具體分析炭序!
視圖正在做動(dòng)畫過(guò)程中,用戶將視圖removeFromSuperView苍日,視圖的生命周期并沒(méi)有結(jié)束惭聂,而是由動(dòng)畫對(duì)應(yīng)的block延續(xù)。視圖可能會(huì)持有1. 強(qiáng)引用模塊相恃,如子視圖 2. 弱引用模塊辜纲,如數(shù)據(jù)源。對(duì)于第一種拦耐,則在視圖真正dealloc的時(shí)候進(jìn)行回收耕腾;對(duì)于第二種,則應(yīng)該在管理者析構(gòu)視圖的時(shí)候杀糯,將弱引用提前致空扫俺,防止出現(xiàn)不安全的訪問(wèn)操作。在這個(gè)案例中固翰,對(duì)象沒(méi)有進(jìn)行dealloc時(shí)狼纬,都應(yīng)該處于生命周期中(內(nèi)存泄露除外),則應(yīng)該要保證對(duì)象所有邏輯合法安全倦挂。