iOS中的各種Timer(含實例代碼)

編寫App工程中,會遇到各種定時器的問題:比如某個頁面上的數(shù)據(jù)定時刷新,需要在定時器中反復(fù)向服務(wù)器發(fā)送請求;首頁廣告位(Banner)的圖片不斷滾動,需要在定時器中設(shè)定變換的間隔時間;收到用戶手勢交互時,出現(xiàn)響應(yīng)動畫,可以通過定時器設(shè)置不同動畫連續(xù)執(zhí)行等等。iOS中的Timer可以通過三種方式來實現(xiàn):NSTimer,dispatch,CADisplayLink,其執(zhí)行的精確度依次提高。下面介紹一下各自的使用方式。

NSTimer

NSTimer是OC以面向?qū)ο蠓绞椒庋b的Timer對象,從其類文檔中可以看到它的兩種創(chuàng)建方式:timer和scheduledTimer。

self.timer = [NSTimer timerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) 
    NSLog(@"timer");
}];

self.timer = [NSTimer timerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) 
    NSLog(@"timer");
}];

[self.timer fire];
[self.timer invalidate];

timerWithTimeInterval創(chuàng)建的timer, 在fire后喚醒;
scheduledTimerWithTimeInterval創(chuàng)建的timer, 創(chuàng)建后立即喚醒;
timer在invalidate后停止。

dispatch

利用多線程GCD創(chuàng)建的Timer,精確度更高,也可以通過參數(shù)設(shè)置Timer首次執(zhí)行時間。

 __block int count = 3;
 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
 //通過start參數(shù)控制第一次執(zhí)行的時間,DISPATCH_TIME_NOW表示立即執(zhí)行
 dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
 dispatch_source_set_event_handler(timer, ^{
     NSLog(@"dispatch_source_set_timer start");
     NSLog(@"%zd", count);
     if (count == 0) {
         dispatch_source_cancel(timer);
     }
     count--;
 });
 NSLog(@"main queue");
 dispatch_resume(timer);
CADisplayLink

CADisplayLink是和iOS界面刷新效率同步執(zhí)行,可以在1s內(nèi)執(zhí)行60次,執(zhí)行效率最高。如果屏幕滑動時卡頓,可以用它來檢測屏幕屏幕刷新頻率。當(dāng)然,不能在其執(zhí)行方法中加載大量任務(wù),否則手機內(nèi)存會急劇增高。

@property (nonatomic, strong) CADisplayLink *link;
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, assign) NSTimeInterval lastTime;
@property (nonatomic, assign) NSInteger count;

self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
[self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

- (void)tick: (CADisplayLink *)link {
    if (self.lastTime == 0) {
        self.lastTime = link.timestamp;
        return;
    }
    
    self.count++;
    NSLog(@"%f", link.timestamp);
    NSTimeInterval delta = link.timestamp - self.lastTime;
    if (delta < 1) return;
    self.lastTime = link.timestamp;
    float fps = _count / delta;
    self.label.text = [NSString stringWithFormat:@"%0f", fps];
    self.count = 0;
}
Tips:NSRunLoop

iOS應(yīng)用執(zhí)行的方式,采用了RunLoop的消息循環(huán),簡要來說啟動后整個應(yīng)用就進(jìn)入一個死循環(huán),應(yīng)用中的所有事件(各種手勢,交互功能(Target-Event)等)在死循環(huán)中被檢測后加入到消息隊列,然后不斷執(zhí)行。

每一線程中都有一個RunLoop,只不過子線程中的RunLoop默認(rèn)關(guān)閉。通過[[NSRunLoop currentRunLoop] run]的方法可以喚醒子線程的RunLoop。

RunLoop中的模式有兩種: kCFRunLoopDefaultMode和UITrackingRunLoopMode。kCFRunLoopDefaultMode也即是iOS開發(fā)文檔中的NSDefaultRunLoopMode,NSRunLoopCommonModes是上述兩種mode的組合。主線程的RunLoop在UIScrollView滑動時會切換成UITrackingRunLoopMode,如果將Timer添加到NSDefaultRunLoopMode,就會在滑動手勢下停止執(zhí)行。

關(guān)注和喜歡都是對我的鼓勵和支持~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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