關於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";
})