关于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";
})