iOS便利NSTimer

為什么要寫這篇破事水

這些代碼來自于年初某短視頻巨廠面試時(shí)候的即興表演,
當(dāng)時(shí)寫的是偽代碼,現(xiàn)在把他補(bǔ)完整
面試官提出來的要求如下:


NSTimer用起來有很多注意點(diǎn),不方便,要求實(shí)現(xiàn)一個(gè)
+ (NSTimer *)xx_scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

1.解決循環(huán)引用
2.aTarget釋放時(shí)自動(dòng)invalidate
3.多個(gè)timer可以同時(shí)存在


那他滿意了嗎

看他笑的挺滿意的,那一輪面試也確實(shí)過了,可惜二面沒表現(xiàn)好……我懷疑是被白剽思路(不可能的你想太多了)

那在哪里可以拿到demo呢?

GitHub - DTD1031/EasyTimer

那怎么實(shí)現(xiàn)

當(dāng)時(shí)思考了2分鐘拿出以下方案,大致就是用了備用接收者和完整消息轉(zhuǎn)發(fā)來完成這個(gè)方法,貼一點(diǎn)關(guān)鍵代碼,完整demo代碼在上面的github里

  1. NSTimer+Easy方法
+ (NSTimer *)clc_scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo {

    CLCTimerObject *obj = [[CLCTimerObject alloc] init];
    obj.target = aTarget; //weak
    obj.myTimer = [NSTimer scheduledTimerWithTimeInterval:ti target:obj selector:aSelector userInfo:userInfo repeats:yesOrNo];
    //timer 持有obj,obj弱引用aTarget,obj同時(shí)也負(fù)責(zé)處理aTarget釋放時(shí)timer的invalidate
    return obj.myTimer;
}

2.CLCTimerObj屬性

//一個(gè)持有aTarget,一個(gè)持有timer,都是弱引用,反正timer啟動(dòng)了就會(huì)被掛住
@property (nonatomic, weak) NSObject *target;
@property (nonatomic, weak) NSTimer *myTimer;

3.CLCTimerObj實(shí)現(xiàn)
//用runtime的備用接收者機(jī)制去判斷aTarget釋放了沒

- (id)forwardingTargetForSelector:(SEL)aSelector {
    //target還沒釋放  --> 返回的是self.target對象
    //target被釋放了  --> 返回的是nil,進(jìn)入下一步消息轉(zhuǎn)發(fā)
    NSLog(@"send to aTarget");
    return self.target;
}

//用完整消息轉(zhuǎn)發(fā)兜底,上一步返回nil時(shí)就invalidate掉timer

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
    NSLog(@"return Signature");
    return [NSMethodSignature signatureWithObjCTypes:"v@:@@"]; //隨便簽,無所謂啦
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    NSLog(@"call forwordInvocation");
    [self _invalidateTimer];
}


- (void)_invalidateTimer {
    if (self.myTimer) {
        [self.myTimer invalidate];
        self.myTimer = nil;
    }
}

利弊分析

好處

1.防止發(fā)生循環(huán)引用、timer沒有好好手動(dòng)invalidate等問題,傻瓜式timer(只是做保護(hù),還是建議手寫invalidate)

2.一次性倒計(jì)時(shí)View(比如543210開始直播)不需要把timer掛住當(dāng)屬性,時(shí)間到了自己removeFromSuperview引用計(jì)數(shù)歸零變成nil就行了,不需要管timer,他是自動(dòng)的

3.自動(dòng)停止能確保NSTimer的invalidate和init在同一個(gè)線程里

孬處
  1. 維護(hù)起來不容易閱讀(“我艸這timer啥時(shí)候釋放的?”)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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