runLoop 添加timer的正確方式 (ios oc)

關於runloop的知識請自行補腦。

當項目中需要啓動計時器進行計數的時候,往往直接添加到主線程上(默認方式,刷新ui方便),但是會導致諸如:tableview滑動事件、ui操作、app後臺切換的時候影響計時的準確性設置導致計時器停止,先來看一般的添加方式:

方式:主線程(NSDefaultRunLoopModes):

[NSThread detachNewThreadSelector:@selector(startTimer) toTarget:self withObject:nil];//此方式雖然在子線程,但是不推薦(ui刷新有問題和nsrunloopmodes的依賴,導致該方法不徹底)
本質和下面直接寫類似:

[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerFire) userInfo:nil repeats:YES];

- (void)startTimer
{
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerFire) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop]run];
}

- (void)timerFire
{
    self.intervalTimespan -= 1;
    [self performSelectorOnMainThread:@selector(updateSendRequestBtnTitle) withObject:nil waitUntilDone:YES];
    if (0 >= self.intervalTimespan) {
        [self.timer invalidate];
        return;
    }
}

正確姿勢一:修改NSRunLoopCommonModes,然後用addTimer方式:

if(self.timer){
[self.timer invalidate];
self.timer = nil;
}
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerFire) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

正確姿勢二:子線程

 NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(startTimer) object:nil];
  [thread start];

- (void)startTimer
{
    
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerFire) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop]run];

}
刷新:
- (void)timerFire
{
    self.intervalTimespan -= 1;
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateSendRequestBtnTitle];
    });
    if (0 >= self.intervalTimespan) {
        [self.timer invalidate];
        return;
    }
}

正確姿勢三:GCD

<pre name="code" class="objc">   uint64_t interval = 0.01 * NSEC_PER_SEC;
    dispatch_queue_t queue = dispatch_queue_create("timer queue", 0);
    
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, interval,  0);
    __weak UIViewController *weakSelf = self;
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"Timer:%@",[NSThread currentThread]);
        [weakSelf  timerFire];
    });
    dispatch_resume(timer);



刷新:timerFire中:

    dispatch_async(dispatch_get_main_queue(), ^{
        self.label.text = @"something";
    })





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章