原创
定时器里面有个runloop mode,一般定时器是运行在defaultmode上。但是如果滑动了这个页面,主线程runloop会转到UITrackingRunLoopMode中,这时候就不能处理定时器了,造成定时器失效,原因就是runroop mode的问题
NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
:默认,空闲状态UITrackingRunLoopMode
:ScrollView滑动时会切换到该ModeUIInitializationRunLoopMode
:run loop启动时,会切换到该ModeNSRunLoopCommonModes(kCFRunLoopCommonModes)
这里提供了两种解决办法:
1. 把定时器添加到当前线程消息循环中 并指定消息循环的模式为
NSRunLoopCommonModes(无论runloop运行在哪个mode,都能运行)
2. 切换到主线程上更新UI
// 步骤1. 把NSTimer放到子线程中,但是要注意:因为自线程的消息循环默认不开启,所以这里还需要开启一下子线程的消息循环
// 步骤2. 切换到主线程上更新UI
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)UIScrollView *scrollView;
@property(nonatomic,strong)NSTimer *timer;
@property(nonatomic,strong)UILabel *label;
@property(nonatomic,assign)float times;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.scrollView = [[UIScrollView alloc]init];
self.scrollView.frame = self.view.frame;
self.scrollView.backgroundColor = [UIColor cyanColor];
self.scrollView.contentSize = CGSizeMake(375, 2000);
[self.view addSubview:self.scrollView];
self.label = [[UILabel alloc]init];
self.label.frame = CGRectMake(100, 100, 100, 100);
self.label.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.label];
_times = 0;
//self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(demo) userInfo:nil repeats:YES];
// 解决方法1: 把定时器添加到当前线程消息循环中 并指定消息循环的模式为
// cNSRunLoopCommonModes(无论runloop运行在哪个mode,都能运行)
// 加上这句完美解决
//[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
// 解决方法2:
// 1. 把NSTimer放到子线程中,但是要注意:因为自线程的消息循环默认不开启,所以这里还需要开启一下子线程的消息循环
// 2. 切换到主线程上更新UI
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(demo) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
-(void)demo{
_times+=0.1;
//self.label.text = [NSString stringWithFormat:@"%f",_times];
// 队列方式(在主线程上更新UI)
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.label.text = [NSString stringWithFormat:@"%f",_times];
}];
// GCD方式
/*dispatch_async(dispatch_get_main_queue(), ^{
self.label.text = [NSString stringWithFormat:@"%f",_times];
});*/
}
@end