NSTimer
NSTimer是Foundation框架中一種很方便很有用的對(duì)象兵迅,可以:
- 指定絕對(duì)的日期和時(shí)期吭历,以便到時(shí)執(zhí)行指定任務(wù)
- 指定執(zhí)行任務(wù)的相對(duì)延遲時(shí)間
- 指定重復(fù)運(yùn)行的任務(wù)
計(jì)時(shí)器要和run loop
(運(yùn)行循環(huán))相關(guān)聯(lián)橙数,run loop
到時(shí)候會(huì)觸發(fā)任務(wù)。創(chuàng)建NSTimer時(shí),可以將其預(yù)先安排在當(dāng)前run loop
中衡招,也可以先創(chuàng)建好,然后手動(dòng)調(diào)用加入run loop
中每强,它才能正常觸發(fā)任務(wù)始腾。
系統(tǒng)方法:
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
target:(id)target
selector:(SEL)aSelector
userInfo:(nullable id)userInfo
repeats:(BOOL)repeats;
直接創(chuàng)建個(gè)實(shí)例對(duì)象,并將其加入當(dāng)前run loop
當(dāng)中空执。由于計(jì)時(shí)器會(huì)保留目標(biāo)對(duì)象target浪箭,所以反復(fù)執(zhí)行任務(wù)通常會(huì)導(dǎo)致應(yīng)用程序問(wèn)題。也就是設(shè)置重復(fù)執(zhí)行模式的那種計(jì)時(shí)器辨绊,很容易引入retain cycle
(保留環(huán))奶栖。
如何打破Retain Cycle
- MSWeakTimer
- 為NSTimer添加個(gè)handlerBlock
推薦MSWeakTimer:
線程安全的Timer,不會(huì)對(duì)target進(jìn)行retain操作门坷,支持GCD Queue宣鄙,NSTimer的替代品MSWeakTimer現(xiàn)已支持Pod,具體實(shí)現(xiàn)及用法請(qǐng)點(diǎn)擊這里
下面主要談?wù)劦诙N默蚌,如何自己實(shí)現(xiàn)來(lái)打破retain cycle
冻晤。
1.為NSTimer添加一個(gè)Category方法
NSTimer+WeakTimer.h
+ (NSTimer *)zx_scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
repeats:(BOOL)repeats
handlerBlock:(void(^)())handler;
NSTimer+WeakTimer.m
+ (NSTimer *)zx_scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
repeats:(BOOL)repeats
handlerBlock:(void(^)())handler
{
return [self scheduledTimerWithTimeInterval:timeInterval
target:self
selector:@selector(handlerBlockInvoke:)
userInfo:[handler copy]
repeats:repeats];
}
+ (void)handlerBlockInvoke:(NSTimer *)timer
{
void (^block)() = timer.userInfo;
if (block) {
block();
}
}
2.如何使用這個(gè)Category方法
創(chuàng)建一個(gè)NSTimer
- (void)startPolling
{
__weak typeof(self)weakSelf = self;
self.timer = [NSTimer zx_scheduledTimerWithTimeInterval:5.0 repeats:YES handlerBlock:^void(void){
__strong typeof(weakSelf)strongSelf = weakSelf;
[strongSelf doPolling];
}];
}
執(zhí)行輪詢?nèi)蝿?wù)slector
- (void)doPolling
{
//Todo...;
}
銷毀NSTimer對(duì)象
- (void)stopPolling
{
[self.timer invalidate];
self.timer = nil;
}
- (void)dealloc
{
[self.timer invalidate];
}
計(jì)時(shí)器現(xiàn)在的targer是NSTimer類對(duì)象。這段代碼先是定義了個(gè)弱引用绸吸,令其指向self,然后block捕獲這個(gè)引用鼻弧,而不直接去捕獲普通的self變量,也就是說(shuō)self不會(huì)為計(jì)時(shí)器所保留锦茁。當(dāng)block開始執(zhí)行時(shí)攘轩,立刻生成strong強(qiáng)引用,以保證實(shí)例在執(zhí)行期間持續(xù)存活码俩,不被釋放撑刺。
采用這種寫法后,外界指向NSTimer的實(shí)例最后一個(gè)引用被釋放后握玛,則創(chuàng)建NSTimer的實(shí)例也隨之被系統(tǒng)回收够傍。
Refer: Effective Objective-C 2.0 Tips52