通过以下文章学习记录
RunLoop: 消息循环、运行循环、跑圈
RunLoop内部实际是一个do-while循环
RunLoop在第一次获取时创建,线程结束时销毁;子线程不手动获取RunLoop,它一直不会存在
一个RunLoop可以有多个mode, 每个mode包含若干个mode item: source(set对象)、timer(array对象)、observer(array对象)
由于每个mode都是一个mutableset对象,因此item被重复加入同一个mode不会有效果;当mode中不存在item时,RunLoop退出,换句话说,mode中不存在item时,调用 runloop run方法也不会执行
+ source0: 使用时先调用CFRunLoopSourceSignal(source),标志位待处理,后手动调用CFRunLoopWakeUp(runloop)来唤醒RunLoop, 让处理这个事件
-performSelector:onThread:withObject:waitUntilDone: inModes:创建的是source0任务。
+ source1: 基于port,能主动唤醒runloop
> source1和timer都属于端口事件源,所有的timer都共用一个端口(timer port)
+ timer: CFRunLoopTimerRef, 在预设的时间点唤醒runloop执行回调,不是实时的
+ observer: CFRunLoopObserverRef观察者,监听runloop状态, 不属于runloop事件源
### 休眠与唤醒
依靠系统内核来完成,核心组件Darwin中的Mach。Mach的对象只能通过消息传递的方式实现对象间通信,消息在两个端口(port)间传递。
通过mach_msg()函数接收、发送消息,会触发内核状态切换,当在用户态调用时会触发陷阱机制,切换到内核态完成实际工作。RunLoop休眠时(mach_msg_trap状态)
#### timer正确执行方式
// 参数1:间隔时间 参数2:对象 参数3:方法 参数4:自定义 参数5:是否重复执行NSTimer*timer=[NSTimer timerWithTimeInterval:1target:selfselector:@selector(task)userInfo:nil repeats:YES];//把定时源加入到当前线程下的消息循环中[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
线程中启动runloop,如果想runloop考研终止,使用下面方法
'''
BOOL shouldKeepRunning=YES;//全局变量
NSRunLoop*theRL=[NSRunLoop currentRunLoop];
while(shouldKeepRunning&&[theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
'''
如果没有输入源,runloop马上就退出,解决此问题可以使用
'''
//加个端口的源
[[NSRunLoop currentRunLoop]addPort:[NSPort port]forMode:NSDefaultRunLoopMode];
while(YES&&[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
'''
> 用户触发事件, IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收,SpringBoard会利用mach port,产生source1,来唤醒目标APP的com.apple.uikit.eventfetch-thread的RunLoop。Eventfetch thread会将main runloop 中__handleEventQueue所对应的source0设置为signalled == Yes状态,同时唤醒main RunLoop。mainRunLoop则调用__handleEventQueue进行事件队列处理。
### RunLoop应用
+ 事件响应
+ 手势识别
+ 界面刷新
+ NSTimer
+ PerformSelector:afterDealy/PerformSelectorOnThread(mainThread):
+ dispatch to main queue
+ 线程保活
网友评论