目的:
- 保证线程不退出
- 负责监听事件:触摸、时钟、网络
NSRunLoop模式:
NSDefaultRunLoopMode 默认模式
UITrackingRunLoopMode UI模式
NSRunLoopCommonModes UI和默认(组合模式,不能算是Runloop的一种模式)
UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的
注意:
- UI模式优先级最高
- UI模式只能被UI事件所唤醒
- 在NSRunLoopCommonModes模式下,不可以调用sleep方法,会阻塞主线程
案例 一
界面上半部分有一个滚动的轮播图,下面部分有一个tableview,当tableview滚动的时候,轮播图卡主不动
-
分析
轮播图通过NSTimer控制滚动,运行在主线程
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
NSTimer 创建后被系统加入到Runloop中,使用了NSDefaultRunLoopMode模式
当tableview滚动时,UI线程也就是主线程在执行,
就会执行 UITrackingRunLoopMode模式Runloop的方法,
UI模式的优先级最高,就造成了NSTimer的阻塞,从而导致轮播图卡主不动 -
解决方法:
//创建NStimer NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES]; //加入到Runloop中 [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; //或者 [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
案例 二
先来一段代码
- (void)viewDidLoad {
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSLog(@"来了!!!");
}];
[thread start];
}
- (void)timerMethod{
NSLog(@"come here");
[NSThread sleepForTimeInterval:1.0];
static int a = 0;
a++;
NSLog(@"%d----%@",a,[NSThread currentThread]);
}
代码执行后输出
NSRunLoop[65121:4770362] 来了!!!
-
分析
有耗时操作,肯定会选择放在线程里执行
首先 NSThread 线程内部一定会加入Runloop,但是子线程不会使用到UITrackingRunLoopMode模式。
当代码执行到NSLog(@"来了!!!");
这个线程的Block已经执行完毕,会销毁内部创建的timer以及Runloop,
所以- (void)timerMethod
方法不会执行定义成属性保持住
@property (nonatomic, strong) NSThread *thread;
会发现并没有效果- (void)timerMethod
仍然没有执行!!!
Strong只能保持住OC对象,线程还是会释放,只是在堆内存中存放了一个NSThread的结构体,这时调用[_thread start];
就会Crash。
因为NSthread操作的子线程,这时的子线程已经释放。 -
解决方案
Runloop在第一次获取的时候,就被创建--类似懒加载
Runloop创建之后,默认是不循环的,必须手动开启[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run];
网友评论