
runloop 官网
image
很有意思的是,runloop篇章属于多线程编程指南里面的内容,关于如何在自定义里面配置runloop需要在多线程编程指南里面的文档。
下面介绍了如何探索 runloop,主要分5个知识点
- Run Loops:了解 runloop 是如何工作的;
- Input Modes:runloop 如何使用 input modes 对输入源进行分类
- Getting the Run Loop:如何获取当前 runloop 对象
- Adding Input Sources:如何添加一个输入源到 runloop 中
- Running the Run Loop:进入 runloop 的方法
这篇文章主要是对官网的一个翻译以及补充自己的一些理解
Run Loops
Event-driven applications receive their events in a run loop. A run loop monitors sources of input to the application and dispatches control when sources become ready for processing. When processing is complete, control passes back to the run loop which then waits for the next event. Possible events include mouse and keyboard events from the window system, the arrival of data on ports, the firing of timers, and distributed object requests.
这一段主要讲述了runloop中的事件驱动
。
事件驱动的应用程序在 runloop
中接收它们的事件。runloop
监视应用程序的input source
,并在 source
准备好进行处理时分派控制。当处理完成时,控制传递回 runloop
,然后该循环等待下一个事件。可能发生的事件包括来自窗口系统的鼠标和键盘事件、数据到达端口、触发计时器和分布式对象请求
。
The NSRunLoop class declares the programmatic interface to objects that manage input sources, the objects from which the run loop receives information. There are two general types of input sources to a run loop: asynchronous (input arrives at unpredictable intervals) and synchronous (input arrives at regular intervals). NSPort objects represent asynchronous input sources, and NSTimer objects represent synchronous input sources.
NSRunLoop
类为管理输入源的对象声明编程接口,runloop
从这些对象接收信
息。运行循环有两种一般类型的输入源:
-
异步
(输入以不可预测的时间间隔到达):NSPort
对象表示异步输入源 -
同步
(输入以定期的时间间隔到达):NSTimer
对象表示同步输入源
Besides managing input sources, NSRunLoop also provides support for delayed actions that are event-driven rather than timer driven. NSWindow uses delayed actions to perform screen updates on dirty views. NSNotificationQueue uses them to post notifications queued with the modes NSPostASAP and NSPostWhenIdle. You can request a delayed action with the NSRunLoop method performSelector:target:argument:order:modes:; the indicated method is then sent to the target at the start of the next run loop.
除了管理输入源,NSRunLoop
还提供了对事件驱动而不是计时器驱动的延迟操作的支持。NSWindow
使用延迟操作对脏视图执行屏幕更新。NSNotificationQueue
使用它们来发布 NSPostASAP
和 NSPostWhenIdle
模式下排队的通知。
你可以用 NSRunLoop
方法 performSelector:target:argument:order:modes:
;然后在下一次运行循环开始时将指定的方法发送到目标。
In general, your application does not need to either create or explicitly manage NSRunLoop objects. Each NSThread, including the application’s main thread, has an NSRunLoop object automatically created for it. However, only the main thread in an application using the Application Kit automatically runs its run loop; additional threads (or Foundation Kit tools) have to explicitly run the run loop themselves. To access the current thread’s default run loop, use the NSRunLoop class method currentRunLoop.
- 一般不需要显示创建
NSRunLoop
对象 - 每个NSThread 都有默认创建一个
NSRunLoop
对象 - 主线程的
NSRunLoop
系统会自己启动 - 其他线程的
NSRunLoop
需要手动开启
When an NSRunLoop runs, it polls each of the sources for the input mode to determine if any need processing. Only one is processed per loop. If no input sources are processed, NSRunLoop waits for input from the operating system. The run loop waits until input arrives or a timeout—provided when starting the run loop—is exceeded. At this point, the NSRunLoop may either return or it may continue, depending on which method was used to run the loop.
- 当
NSRunLoop
运行时,它会轮询每个源的输入模式,以确定是否需要处理 - 每个循环只处理一个source
- 如果没有处理输入源,
NSRunLoop
将等待来自操作系统的输入。运行循环将等待 - 运行循环时提供的超时,源码中给出的是 10的10次方,不会超时的
Input Modes
Run loops can be run in different modes. A mode, which is identified by an arbitrary string, defines a collection of input sources that is monitored while the run loop is in that mode. For example, you can have one mode that runs while the application is idle, waiting for all types of events to process, and another that only listens to a particular port, waiting for a response from a distributed object request. You do not want to handle keyboard events in the latter case, since the application has not finished processing an earlier event which caused the distributed object request to be made.
- 运行循环可以在不同的模式下运行
- 模式(由任意字符串标识):定义了在运行循环处于该模式时要监视的输入源集合
- 例如,您可以让一种模式在应用程序空闲时运行,等待处理所有类型的事件
- 而另一种模式只侦听特定端口,等待来自分布式对象请求的响应。您不希望处理键盘事件,因为应用程序尚未完成导致发出分布式对象请求的早期事件的处理。
Input mode | Description |
---|---|
NSDefaultRunLoopMode | 使用这个模式来处理输入源而不是NSConnections。这是最常用的运行循环模式。 |
NSConnectionReplyMode | 使用这个模式来指示等待应答的NSConnection对象。您很少需要使用此模式。 |
NSModalPanelRunLoopMode | 在等待来自模态面板的输入时使用此模式,例如NSSavePanel或NSOpenPanel。 |
NSEventTrackingRunLoopMode | 使用此模式进行事件跟踪循环。 |
Getting the Run Loop
When using an application built using the Application Kit, a run loop is created and run automatically. If you need to access this run loop, use the NSRunLoop class method currentRunLoop.
Additional run loops are created for each additional NSThread and also can be accessed by invoking currentRunLoop from each thread. These run loops do not have any input sources and are not running when the thread begins. You must add input sources to them and start the run loop yourself.
- 每个线程都会创建一个 runloop,不需要手动创建
- 子线程的 runloop 默认没有输入源,需要添加 input source 才能启动 runloop
- runloop 是非线程安全的,不能获取其他线程的 runloop
- 通过方法
currentRunLoop
即可获取一个 runloop
Adding Input Sources
1. 手动添加输入源 input source
In most cases, input source objects add themselves to the current run loop as needed, but you can add them manually to get greater control over their behavior.
2. NSTimer 类方法
The NSTimer class method scheduledTimerWithTimeInterval:invocation:repeats:, for example, creates a new timer object and adds it to the NSDefaultRunLoopMode mode of the current run loop. If you instead create the timer with timerWithTimeInterval:invocation:repeats:, you must add it manually to the run loop with the NSRunLoop instance method addTimer:forMode:, which allows you to specify a different mode.
scheduledTimerWithTimeInterval:invocation:repeats:
这个方法会创建一个 timer
,并将这个 timer
添加到 NSDefaultRunLoopMode
模式下
timerWithTimeInterval:invocation:repeats:
这个方法创建一个 timer
,但不会添加到 runloop
中,需要手动添加 timer
到 runloop
中,使用 addTimer:forMode:
方法添加到 runloop
的 指定mode
中
3. NSPort 对象
NSPort objects are usually used as part of an NSConnection, which automatically adds its receive port to the appropriate modes as needed. If you have a stand-alone port object, you can manually add it to the run loop with the NSRunLoop method addPort:forMode:.
使用 addPort:forMode:
给 runloop 的某种 mode
,添加一个 port
,作为线程间通信的一个通道。
Running the Run Loop
1. run
使用 run
,让一个 runloop
运行起来,直到 NSDefaultRunLoopMode
中的所有输入源被移除,runloop
会立即返回(也就是进入休眠状态)
[[NSRunLoop currentRunLoop] run];
2. runUntilDate:
运行到指定时间才结束
[[NSRunLoop currentRunLoop] runUntilDate:aDate];
3. runMode:beforeDate:
while ( [[NSRunLoop currentRunLoop] runMode:NSModalPanelRunLoopMode
beforeDate:[NSDate distantFuture]] );
给定一个确切的时间,runloop
只会运行一次,要么是单个输入源被处理之后返回,要么是达到了 beforeDate
指定的时间返回。
给一个未来时间,runloop
会一直运行下去,返回值表示 runloop
是否在运行,如果输入源是空的,runloop
也会结束运行。
4. runloop 条件化
条件化是什么意思呢?我们可以指定一个runloop退出的条件。上面知道了一般情况下 runMode:beforeDate:
只会运行一次,那我们可以将放到一个 do-while
循环里面,通过自定义的逻辑来控制这个循环退出的条件。例如下面代码中的 endRunLoop
变量,当 endRunLoop=YES
的时候,循环结束
double resolution = 1.0;
BOOL endRunLoop = NO;
BOOL isRunning;
do {
NSDate* next = [NSDate dateWithTimeIntervalSinceNow:resolution];
isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:next];
} while (isRunning && !endRunLoop);
上面这些内容都是非常简单的介绍了 runloop 的一些大致情况,对于底层探索,仅仅了解这些知识是肯定不够的,后面会分两个章节来讲解 runloop:
- runloop 在多线程中的使用
- runloop 源码探索
网友评论