消息循环
消息循环在主线程上的使用
- 消息
我们可以简单的把消息理解为用户的输入事件 - 循环
什么是RunLoop
- runloop就是消息循环,每个线程内部都有一个消息循环。
- 只有主线程的消息循环默认开启,子线程的消息循环默认不开启。
RunLoop目的
- 保证程序不退出
- 负责处理输入事件
- 如果事件没有发生,会让程序进入休眠状态
事件类型
- input source(输入源)&Timer source(定时源)
输入源可以是键盘鼠标,NSPort,NSConnection等对象,定时源是NSTimer事件

如何使用
(1)创建输入源(NSTimer为例)
(2)指定该事件(源)在循环运行中的模式,并且加入循环
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

下面的代码示例可以比喻为,一个患牙病的人应该去综合性医院而不应该去妇产科医院就诊
- (void)demo{
// 创建NSTimer
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(task) userInfo:nil repeats:YES];
// 把定时源加入到当前线程下消息循环中
// 参数1: 定时源
// 参数2: NSDefaultRunLoopMode
/**
现象:
NSDefaultRunLoopMode 拖动界面,定时源不运行
NSRunLoopCommonModes 拖动界面不受影响(KCFRunloopDefaultMode,UITrackingRunloopMode都是其中的一种)
没有拖动界面 KCFRunloopDefaultMode
拖动界面 UITrackingRunloopMode
*/
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
使用总结
(1)创建消息
(2)把消息放进循环
(3)在于循环的模式匹配的时候,消息运行
消息循环在子线程上的使用
特点:自线程默认不开启消息循环,主线程默认开启消息循环
// 子线程的消息循环
-(void)demo2{
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(task2) object:nil];
thread.name = @"新创建的子线程";
[thread start];
// 往指定线程的消息循环中加入源
[self performSelector:@selector(addTask) onThread:thread withObject:nil waitUntilDone:NO];
}
-(void)task{
NSLog(@"task is running");
}
-(void)task2{
NSLog(@"%@",[NSRunLoop currentRunLoop].currentMode);
// 输出当前的线程
NSLog(@"task2 is running %@", [NSThread currentThread]);
// 开启消息循环 使用run方法无法停止消息循环
// 方法一
// [[NSRunLoop currentRunLoop] run];
// 方法二 改方法受机器性能的影响很大,很老的机器并不一定可以两秒钟内停止这个runloop
// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
// 方法三 apple推荐的方式
// BOOL shouldKeepRunning = YES; //全局的
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
}
NSLog(@"runloop over!!!");
}
-(void)addTask{
NSLog(@"addTask is running");
}
网友评论