我們時常遇到這樣的情況,tableview上面有一個計時的NSTimer障贸,當(dāng)tableView(scrollView)滑動的時候胧辽,NSTimer就失效了。
NSTimer 為什么會失效俄讹,牽扯到了 runloop 這個概念哆致,如果對 runloop 不了解的話,請先閱讀ibireme大神的這篇博客 深入理解RunLoop
我們通常這樣創(chuàng)建timer
// 這種創(chuàng)建方式默認(rèn)將 timer 加入到了 NSDefaultRunLoopMode 模式下
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(startTimer) userInfo:nil repeats:YES];
或者這樣
self.timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(startTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode: NSDefaultRunLoopMode];
以上面兩種寫法颅悉,都是將定時器Timer加入到當(dāng)前的主線程沽瞭,并且當(dāng)前主線程runloop的mode為NSDefaultRunLoopMode
,這個模式也是runloop的默認(rèn)模式剩瓶。
我們不滑動 scrollview 的時候主線程的runloop 停留在NSDefaultRunLoopMode
模式驹溃,這個時候定時器Timer是有效的,但當(dāng)我們滑動 scrollview 的時候延曙, 主線程的runloop 會切換到 UITrackingRunLoopMode
模式豌鹤,這個時候因?yàn)槎〞r器Timer 是在NSDefaultRunLoopMode
模式下,所以主線程的 runloop 不能處理定時器枝缔,定時器也就理所當(dāng)然失效布疙,當(dāng)停止滑動,runloop 的模式切換回NSDefaultRunLoopMode
愿卸,定時器才會重新生效灵临。
明白了失效的原因,解決問題也就簡單了趴荸,有兩種辦法儒溉。
第一種:更改線程 runloop 的mode
self.timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(startTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode: NSRunLoopCommonModes];
NSRunLoopCommonModes
是runloop中的另一種模式,其作用等價于NSDefaultRunLoopMode
與UITrackingRunLoopMode
的結(jié)合发钝,滑動scrollview的時候等價于UITrackingRunLoopMode
顿涣,停止滑動的時候等價于UITrackingRunLoopMode
波闹。
第二種:將定時器放到到子線程里面創(chuàng)建。
// 創(chuàng)建一個子線程
[NSThread detachNewThreadSelector:@selector(createTimer) toTarget:self withObject:nil];
// 在子線程里創(chuàng)建定時器
- (void)createTimer {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(startTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}