第52條:別忘了NSTimer會(huì)保留其目標(biāo)對(duì)象

計(jì)時(shí)器會(huì)保留目標(biāo)對(duì)象,等到自身“失效”時(shí)再釋放此對(duì)象。調(diào)用invalidate方法可令計(jì)時(shí)器失效;執(zhí)行完畢相關(guān)任務(wù)后,一次性的計(jì)時(shí)器也會(huì)失效。開(kāi)發(fā)者若將計(jì)時(shí)器設(shè)置成重復(fù)執(zhí)行模式,那么必須自己調(diào)用invalidate方法,才能令其停止。

由于計(jì)時(shí)器會(huì)保留其目標(biāo)對(duì)象,所以反復(fù)執(zhí)行任務(wù)通常會(huì)導(dǎo)致應(yīng)用程序出問(wèn)題。也就是說(shuō),設(shè)置成重復(fù)執(zhí)行模式的那種計(jì)時(shí)器,很容易引入“保留環(huán)”。如果此環(huán)能在某一時(shí)刻打破,那就不會(huì)出什么問(wèn)題。

然而想要打破保留環(huán),只能改變實(shí)例變量或者令計(jì)時(shí)器失效。

[_pollTimer invalidate];
_pollTimer = nil;

要么令系統(tǒng)將此實(shí)例回收,只有這樣才能打破保留環(huán)。

但是有些時(shí)候 你是想控制器銷毀時(shí)候去銷毀定時(shí)器的,你肯定會(huì)說(shuō),那我們?cè)赿ealloc里執(zhí)行[invalidate]不就好了。好了,如果你說(shuō)這句話,說(shuō)明你沒(méi)有理解NSTimer的工作了。

你可以回頭看看我寫的

“當(dāng)我們新建一個(gè)timer時(shí)候,timer都會(huì)去對(duì)target對(duì)象持有一份,以保證timer還活著的時(shí)候,控制器不會(huì)被銷毀”

也就是說(shuō) 只要timer活著,控制器就不會(huì)被銷毀,dealloc也就不會(huì)被執(zhí)行。所以在dealloc里調(diào)用indalidate方法是沒(méi)有效果的。我們暫且把這種現(xiàn)象稱為NSTimer的保留環(huán)問(wèn)題。

2)那我們?nèi)绾稳ソ鉀Q這個(gè)問(wèn)題呢,當(dāng)然就是想要timer不要對(duì)控制器的方法強(qiáng)持有。

解決的方法是在NSTimer 的基礎(chǔ)上,建一個(gè)分類(Category) 并實(shí)現(xiàn)一個(gè)類方法,這里我們叫做:

+(NSTimer *)kscheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)repeats;

//接口部分

@interface NSTimer (CLBlockSupport)
+(NSTimer *)kscheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;
@end

//實(shí)現(xiàn)部分

@implementation NSTimer (CLBlockSupport)
+(NSTimer *)kscheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)repeats
{    
return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(clblockInvoke:)userInfo:[block copy]repeats:repeats];
}

+(void)clblockInvoke:(NSTimer*)timer
{   
    void(^block)()=timer.userInfo;   
    if (block) 
    {        
        block();    
    }
}

定義一個(gè)NSTimer的類別,在類別中定義一個(gè)類方法。類方法有一個(gè)類型為塊的參數(shù)(定義的塊位于棧上,為了防止塊被釋放,需要調(diào)用copy方法,將塊移到堆上)。
使用這個(gè)類別的方式如下:
__weak ViewController *weakSelf = self;
_timer = [NSTimer kscheduledTimerWithTimeInterval:5.0 block:^{ __strong ViewController *strongSelf = weakSelf;
[strongSelf startCounting]; } repeats:YES];

使用這種方案就可以防止NSTimer對(duì)類的保留,從而打破了循環(huán)引用的產(chǎn)生。__strong ViewController *strongSelf = weakSelf
主要是為了防止執(zhí)行塊的代碼時(shí),類被釋放了。
在類的dealloc方法中,記得調(diào)用[_timer invalidate]。

最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

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