以下内容均来自互联网,但属于个人摘录总结,主要分析一下“只有当消息循环的模式与事件模式匹配时,消息循环才会运行”这句话的模式匹配,是哪些模式匹配哪些模式。
每个线程都有一个消息循环,主线程消息循环默认开启,子线程消息循环默认都是关闭的,需要手动开启。消息循环与线程之间是一一对应的关系,其关系保存在一个全局字典里面(字典的key为线程,value为消息循环)。
你只能在线程结束时销毁消息循环。除了主线程即UI线程,你只能在线程内部获取消息循环。
为消息循环添加事件,事件有两种类型:
- 输入源:异步传递事件,通常是来自不同的线程或不同的应用的消息。输入源异步传递事件到对应的处理程序和在线程关联的NSRunLoop对象调起runUntilDate:方法来退出事件处理。
- 定时源:同步地传递事件,发生在每个定时器调用或周期性地调用。Timer源传递事件到他们的处理程序,但是不会调用run loop来退出处理。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self demo];
}
-(void) demo{
NSTimer* timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(task) userInfo:nil repeats:YES];//创建定时源 指定定时源执行的方法
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//将该定时源加入到当前线程下的消息循环中,指定消息循环模式为NSRunLoopCommanModes
}
-(void) task{
NSLog(@"%@",[[NSRunLoop currentRunLoop] currentMode]); //输出当前消息循环的模式
NSLog(@"我是输入事件的定时源指定的执行方法");
}
注意上面代码中,[[NSRunLoop currentRunLoop] currentMode]是指当前消息循环的模式,而消息循环模式是输入源和定时源的一个集合,这个集合会被监听.
每次启动运行循环,可以指定一个特殊的模式,在运行循环执行期间,只有跟特定的模式相关联的事件源才会被监听以及允许传递它们的事件,跟其它模式相关联的事件源将不会被监听。
上述代码执行结果
我在故事板中添加了一个textView,上述代码中指定的消息循环模式为NSRunLoopCommanModes。拖动textView时消息循环模式为UITrackingRunLoopMode,松开后为KCFRunLoopDefaultMode,事件发生改变,对应消息循环模式也发生了改变。
iOS消息循环的两个对象是NSRunLoop和CFRunLoop,前者是对后者的封装。
CFRunLoop是Core Foundation框架里的对象,提供了纯c API,所有API是线程安全的。
NSRunLoop是Cocoa框架里的对象,是对CFRunLoop的封装,API不是线程安全的。
以下是系统定义的几种消息循环模式
Mode | Name | Description |
---|---|---|
Default |
NSDefaultRunLoopMode(Cocoa) kCFRunLoopDefaultMode (Core Foundation) |
可以用于大多数操作。在大多数时间,应该使用这种模式来启动和设置输入源。 |
Connection | NSConnectionReplyMode(Cocoa) | Cocoa使用这种模式联合NSConnection对象来监听响应。我们很少会自己用到这种模式 |
Modal | NSModalPanelRunLoopMode(Cocoa) | Cocoa使用这种模式来识别为模态面板准备的事件。 |
Event tracking | NSEventTrackingRunLoopMode(Cocoa) | Cocoa使用这种模式来约束鼠标拖拽或其它用户界面追踪循环的事件。 |
Common modes |
NSRunLoopCommonModes(Cocoa) kCFRunLoopCommonModes (Core Foundation) |
这是一个通用的模式组,使用这种模式关联输入源,同样会关联这个模式组里面的每一种模式。对于Cocoa应用来说,这个集合包含了 default、modal以及event tracking模式。 |
Core Foundation初始状态下只包含 default 模式,但是可以通过 CFRunLoopAddCommonMode函数来添加自定义模式。
模式 | 目的 | 普通模式的一部分? |
---|---|---|
kCFRunLoopDefaultMode | 默认的运行循环模式,几乎涵盖所有的来源。 你应该总是添加源和计时器这种模式下,如果没有特别的原因。 可以用符号kCFRunLoopDefaultMode和NSDefaultRunLoopMode进行访问。 | 是 |
NSTaskDeathCheckMode | 通过使用NSTask来检查任务仍在运行。 | 是 |
_kCFHostBlockingMode _kCFNetServiceMonitorBlockingMode _kCFNetServiceBrowserBlockingMode _kCFNetServiceBlockingMode _kCFStreamSocketReadPrivateMode _kCFStreamSocketCanReadPrivateMode _kCFStreamSocketWritePrivateMode _kCFStreamSocketCanWritePrivateMode _kCFStreamSocketSecurityClosePrivateMode _kCFStreamSocketBogusPrivateMode _kCFURLConnectionPrivateRunLoopMode _kProxySupportLoadingPacPrivateMode _kProxySupportSyncPACExecutionRunLoopMode _kCFStreamSocketSecurityClosePrivateMode |
使用各种私人运行的循环模式CFNetwork的阻止操作 | 没有 |
UITrackingRunLoopMode | UI跟踪。 | 是 |
GSEventReceiveRunLoopMode | 接收系统事件。 | 没有 |
com.apple.securityd.runloop | 与securityd通信。 通过使用跳板而已。 | 没有 |
FigPlayerBlockingRunLoopMode | QuickTime的关系。 | 没有 |
在上面提到的一段代码中,循环模式由kCFRunLoopDefaultMode变为UITrackingRunLoopMode,而对程序的输入源事件由默认变为“约束鼠标拖拽或其它用户界面追踪循环的事件”。那就这个例子来说 是不是说明默认事件(大多数操作事件)对应消息循环模式的kCFRunLoopDefaultMode,约束鼠标拖拽或其它用户界面追踪循环的事件对应循环模式的UITrackingRunLoopMode ?
那有没有人能告诉我,既然都是循环模式,执行NSLog(@"%@",[[NSRunLoop currentRunLoop] currentMode]); 为什么控制台输出的是第二个表格的kCFRunLoopDefaultMode和UITrackingRunLoopMode,而不是第一个表格的NSDefaultRunLoopMode和NSRunLoopCommonModes
我是菜鸟啊啊啊,如果知道请评论给我科普一下吧