runloop:原理https://blog.ibireme.com/2015/05/18/runloop/
https://blog.ibireme.com/2015/05/18/runloop/
1. 消息循环概念
RunLoop就是消息循环,每一个线程内部都有一个消息循环。
只有主线程的消息循环默认开启,子线程的消息循环默认不开启。
每个线程都有一个消息循环,主线程消息循环默认开启,子线程消息循环默认都是关闭的,需要手动开启。消息循环与线程之间是一一对应的关系,其关系保存在一个全局字典里面(字典的key为线程,value为消息循环)。
你只能在线程结束时销毁消息循环。除了主线程即UI线程,你只能在线程内部获取消息循环。
子线程的运行循环默认是不启动的。启动运行循环后,如果不停止运行循环,不会执行后续的任何代码,会形成一个死循环。一旦停止了运行循环,后续代码能够执行,执行完毕后,线程被自动销毁。
2. 子线程开启消息循环的3种方式:
(1)开启消息循环 使用run方法后无法停止消息循环。
[[NSRunLoop currentRunLoop] run];
(2)指定循环运行时间
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
(3)apple推荐的方式(了解)
BOOL shouldKeepRunning = YES; //
global设置为global变量,可控制该消息循环的开闭;
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
3. RunLoop的目的:
a. 保证程序不退出 ;
b. 负责处理输入事件;
c. 如果没有事件发生,会让程序进入休眠状态。
4. 2种事件类型:
Input Sources(输入源)和 Timer Sources (定时源)
输入源可以是键盘鼠标,NSPort, NSConnection 等对象;
定时源是NSTimer 事件。
5. 消息循环的使用:
(1)创建消息(即输入源);
(2)指定该事件(源)在循环中运行的模式,并加入循环;
(3)当事件的模式与消息循环的模式匹配的时候,消息才会运行。
6. 循环常用模式:
(1) NSDefaultRunLoopMode—默认模式(最常用的循环模式)
The mode to deal with input sources other than NSConnection objects. This is the most commonly used run-loop mode. Available in iOS 2.0 and later.
(2) NSRunLoopCommonModes—普通模式(一组模式的集合)
Objects added to a run loop using this value as the mode are monitored by all run loop modes that have been declared as a member of the set of “common" modes; see the description of CFRunLoopAddCommonMode for details.
NSTimer *time=[NSTimerscheduledTimerWithTimeInterval:1target:selfselector:@selector(time)userInfo:nilrepeats:YES];
[[NSRunLoopmainRunLoop]addTimer:timeforMode:NSRunLoopCommonModes];
事件在消息循环中的运行原理:
事件(即定时源Timer)模式有两种:NSDefaultRunLoopMode(默认模式),NSRunLoopCommonModes(包含kCFRunLoopDefaultMode,UITrackingRunLoopMode);
主线程消息循环模式也有两种:kCFRunLoopDefaultMode(默认模式),UITrackingRunLoopMode。
当事件模式与消息循环模式相匹配的时候,消息才会运行。
现象:
当设置事件模式为NSDefaultRunLoopMode 时,拖动UITextView界面,定时源停止运行;当停止拖动,定时源又继续运行;
当设置事件模式为NSRunLoopCommonModes 时,拖动UITextView界面,定时源持续运行不受影响。
此外,当设置事件模式为NSRunLoopCommonModes
时,
未拖动UITextView界面时,消息循环的模式为kCFRunLoopDefaultMode
;
当拖动UITextView界面时,消息循环的模式自动变为UITrackingRunLoopMode
[[NSRunLoop currentRunLoop] currentMode]是指当前消息循环的模式,而消息循环模式是输入源和定时源的一个集合,这个集合会被监听.
每次启动运行循环,可以指定一个特殊的模式,在运行循环执行期间,只有跟特定的模式相关联的事件源才会被监听以及允许传递它们的事件,跟其它模式相关联的事件源将不会被监听。
与其它模式想关联的源,直到随后在合适的模式通过循环后,都会接收到新的事件(比如,将timer加入run loop default模式下,当滚动时,timer不会收到回调,直到停止滚动回到default模式下)。
NSDefaultRunLoopMode: 时钟,网络。发生用户交互的时候,定时源不运行,时钟会被暂停
NSRunLoopCommonModes: 用户交互,响应级别高。 发生用户交互的时候,定时源运行,时钟仍然会触发,如果时钟触发方法非常耗时, 使用此方式时用户操作会造成非常严重的卡顿。
没有拖动界面:kCFRunLoopDefaultMode模式
拖动界面:UITrackingRunLoopMode模式
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) | 公共模式,在任何模式下都可以接收。使用这种模式关联输入源,同样会关联这个模式组里面的每一种模式。 |
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的关系。 | 没有 |
每一次消息循环开始的时候或者主线程捕捉到事件就会先创建自动释放池,执行事件对应的方法,把对象和临时变量保存到自动释放池,运行循环结束前,会释放自动释放池。
自动释放池被销毁或耗尽时,会向池中所有对象发送 release 消息,释放所有 autorelease 的对象。