定時(shí)器

參考文檔1
參考文檔2

1.NSTimer

創(chuàng)建NSTimer

//常用方法
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;

//常用方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep
  • scheduledTimerWithTimeInterval 方法相比timerWithTimeInterval,不僅初始化了一個(gè)timer對象,同時(shí)還將該對象放入到當(dāng)前的Runloop中,而后者需要手動(dòng)將timer放入runloop。最重要的是NSTimer只有放到runloop才會生效。(runloop后面會專門寫一下)。
-(void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
  • timer定時(shí)器并不是一個(gè)精確運(yùn)行的,精確運(yùn)行需要用GCDtimer
  • 正常情況下tableView等滾動(dòng)視圖添加timer后,視圖滾動(dòng)后
    RunLoop會將mode切換成TrackingRunLoopMode 不會調(diào)用timer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateUI) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//NSRunLoopCommonModes的意思為,定時(shí)器可以運(yùn)行在標(biāo)記為common modes模式下。
//具體包括兩種: kCFRunloopDefaultMode  和   UITrackingRunloopMode。
[timer fire];

暫停/啟動(dòng)NSTimer

//啟動(dòng),常用方法創(chuàng)建的直接就啟動(dòng)了
[self.timer setFireDate:[NSDate distantPast]];
//暫停
[self.timer setFireDate:[NSDate distantFuture]];

釋放NSTimer

釋放寫在viewWillDisappear!!!!!
[self.timer invalidate];//將timer停止并移出runloop
self.timer = nil;
NSTimer在ARC下
  • 初始化后放到runloop后,除了ViewController外,iOS系統(tǒng)也強(qiáng)引用NSTimer對象。

  • 將timer對象置nil后,會解除VC對timer的中引用。但iOS系統(tǒng)依然對NSTimer和VC存在強(qiáng)引用關(guān)系。(因?yàn)椴⑽唇獬到y(tǒng)對timer的強(qiáng)引用,并且系統(tǒng)為了實(shí)現(xiàn)NSTimer而對VC繼續(xù)保持引用)。所以先對timer 執(zhí)行invalidate(解系統(tǒng)對timer的強(qiáng)引用),再置nil(解除VC對timer引用)。

  • 由于系統(tǒng)和VC對timer的雙重引用,導(dǎo)致dealloc 方法無法執(zhí)行,所以理想的方法是釋放代碼寫在viewWillDisappear方法中。

2.GCD

dispatch source是一個(gè)監(jiān)視某些類型事件的對象。
當(dāng)這些事件發(fā)生時(shí),它自動(dòng)將一個(gè)block放入一個(gè)dispatch queue的執(zhí)行例程中。
    /**
     *  創(chuàng)建dispatch源
     *
     *  @param DISPATCH_SOURCE_TYPE_TIMER 事件源的類型
     *  @param 0                          <#0 description#>
     *  @param 0                          <#0 description#>
     *  @param dispatch_get_main_queue    在哪個(gè)線程上執(zhí)行
     *
     *  @return dispatch_source_t
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    /**
     * @param start 控制計(jì)時(shí)器第一次觸發(fā)的時(shí)刻
     * @param interval 每隔多長時(shí)間執(zhí)行一次
     * @param leeway 誤差值,0表示最小誤差,值越小性能消耗越大
     */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);

    //事件處理的回調(diào)
    dispatch_source_set_event_handler(timer, ^{
        
    });

    // Dispatch source啟動(dòng)時(shí)默認(rèn)狀態(tài)是掛起的,創(chuàng)建完畢之后得主動(dòng)恢復(fù),
    //否則事件不會被傳遞,也不會被執(zhí)行
    dispatch_resume(timer);
    //取消定時(shí)器
    dispatch_cancel(timer);

3.CADisplayLink

CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(disPlay)];
//與NSTimer不同, 需要手動(dòng)添加到RunLoop中, 如果添加的模式是NSDefaultRunLoopMode, 則scrollview滾動(dòng)時(shí), 會阻礙定時(shí)器的執(zhí)行。
//如果是NSRunLoopCommonModes, 則不會阻礙。
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//設(shè)置刷新頻率, 默認(rèn)是每秒60幀, 如果設(shè)置成60就每秒執(zhí)行一次
//但是實(shí)際測試卻發(fā)現(xiàn),設(shè)置60是2秒執(zhí)行一次, 設(shè)置成30才是每秒執(zhí)行一次。但精度依然比NSTimer高
    displayLink.frameInterval = 60;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容