計(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]。