GCD定時器替換NSTimer不準的問題

Deft_MKJing宓珂璟發表於2016-12-26

1.NSTimer會受到RunLoop中Modes的影響;
2.GCD建立的定時器不受RunLoop中Modes影響;

// 如果在子執行緒中建立Timer,那麼當我們add到RunLoop的時候有NSDefaultRunLoopMode和
    // NSRunLoopCommonModes兩種模式可以選擇
    // 這裡不像主執行緒,子執行緒需要建立loop並且run起來,不然是不會連續跑任務的
    // 不準的原因在於,當我們在NSDefaultRunLoopMode模式下跑的時候,我們滾動例如TableView的時候切換到
    // TrackingMode,loop會退出當前mode,重新進入指定的mode,如果NSTimer不是加到NSRunLoopCommonModes
    // 那麼任務跑起來一直在切換,肯定會不準
    NSTimer *timer=  [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];

GCD建立定時器

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // @property (nonatomic,strong) dispatch_source_t timer;
    /**
      建立一個定時器(dispatch_source_t本質還是個OC物件)
      <OS_dispatch_source: 0x6080001d3b00>
     引數1:代表建立一個定時器
     引數4:佇列
     這裡的強引用是因為,當我定時器延時幾秒呼叫的時候,區域性變數就死了,我們需要強引用起來
     */
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    /**
     設定定時器
     引數1:定時器物件
     引數2:GCD dispatch_time_t 裡面的都是納秒 建立一個距離現在多少秒開啟的任務
     引數3:間隔多少秒呼叫一次
     */
    dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), (uint64_t)(1.0 * NSEC_PER_SEC), 0);
    // 設定回撥
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"定時器%@",[NSThread currentThread]);
    });

    // 啟動
    dispatch_resume(self.timer);
}

RunLoop詳解傳送門

相關文章