RunLoop-运行循环
2018-07-13 本文已影响0人
程序萌
runLoop
一个线程一次只能执行一个任务,执行完后线程退出。如果我们需要一个机制,让线程能随时处理事件但并不退出。
消耗很低,睡眠循环
循环监听事件(事件需要处理不主动发起通知,而是把自身状态变成待处理,runloop去循环监听待处理事件,发现后进行处理)
runloop底层实现推测是do_while,死循环
main函数里面用到runloop,保证app不退出,默认是开启的
线程保命:一个线程任务执行完就挂掉,只有任务执行不完,才会保命,这里用runloop对线程进行保命
和多线程结合使用
和JaveScript中的 Event loop相似
runloop死循环存在的目的:
- 保证程序的不退出
- 负责监听事件 触摸、时钟、网络事件 (这些是和硬件有关系的)
- 如果没有事件发生,就让程序进入休眠状态
runloop分类
主线程的runloop (主循环)
- 默认是开启的,是在UIApplicationMain中开启 用到懒加载
子线程的runloop (子循环)
- 默认是关闭的 准确的说采用懒加载创建
- 需要[NSRunLoop currentRunLoop] run];手动开启
- 每一子线程都可以用[NSRunLoop currentRunLoop] run]获取到,但是只有第一次获取的时候才去创建,用了懒加载
- [NSRunLoop currentRunLoop] run]获取到runloop无法被干掉,只有杀死线程,这个线程上的runloop才会消失
runloop模式(五种)
-
默认模式 NSDefaultRunLoopMode
-
UI模式 UITrackingRunLoopMode
- 优先级最高
- 只能被触摸事件触发(如果默认模式也想触发,需要都进行添加)
-
占位模式 NSRunLoopCommonModes
- 不是真正的模式,只是上面2个模式的占位结合
- 相当于上面2种模式都添加
runloop的应用
- 用runloop创建NSTimer
//方式一
NSTimer * timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerModeth) userInfo:nil repeats:YES];
NSRunLoop * mainRunLoop = [NSRunLoop currentRunLoop];
[mainRunLoop addTimer:timer forMode:NSDefaultRunLoopMode];
//方式二,可以直接触发,因为内部自动把timer加入到了runloop中,模式是默认模式NSDefaultRunLoopMode
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerModeth) userInfo:nil repeats:YES];
- 线程之间的通讯
NSThread * runLoopThread = [[NSThread alloc]initWithTarget:self selector:@selector(oneThread) object:nil];
[runLoopThread start];
[self performSelector:@selector(twoThread) onThread:runLoopThread withObject:nil waitUntilDone:YES];
//给线程增加一个run loop 对这个线程进行保活
- (void)oneThread{
// 这里如果waitUntilDone:NO 即不用等待callBack执行完成,直接执行下面的代码
// 如果waitUntilDone:YES即需要等待callBack执行完成后(如果执行完,线程就会释放,选择YES程序会崩溃,需要添加runloop进行线程保活),子线程才会继续执行后面的代码
NSRunLoop * runloop = [NSRunLoop currentRunLoop];
[runloop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[runloop run];
}
- (void)twoThread{
NSLog(@"线程通讯成功");
}
- GCD 内部封装runloop
使用GCD创建定时器
优点:
时间准确
可以实现子线程跑定时器时,操作UI会终止定时的问题
可以使用子线程,解决定时器跑在主线程上卡UI问题
@interface ViewController ()
//dispatch_source_t 设置为成员变量,不然会立即释放
@property(nonatomic,strong) dispatch_source_t timer;
@end
// 创建一个定时器(dispatch_source_t)
/**
何时开始执行第一个任务 DISPATCH_TIME_NOW(现在时间)
1.0 * NSEC_PER_SEC 每隔多长时间执行一次
*/
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 1.0*NSEC_PER_SEC, 0);
// 设置回调
dispatch_source_set_event_handler(_timer, ^{
NSLog(@"设置回调");
});
// 启动定时器
dispatch_resume(_timer);
// 控制器被干掉了之后,打印还在进行,使用下面方法进行关闭
// dispatch_source_cancel(_timer);