内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

iOS RunLoop(1)

2019-03-22 12:04 出处:清屏网 人气: 评论(0

RunLoop 是与线程相关的基础架构中的一部分,它是一个处理事件的循环(线程进入这个循环,运行事件处理程序来响应传入的事件), RunLoop 的目的是当有事件需要处理时,线程是活跃的、忙碌的,当没有事件后,线程进入休眠。

RunLoop结构以及事件来源:

一个 RunLoop 包含若干个 Mode ,每个 Mode 包含若干个 Source / Timer / Observer / Port 。当启动一个 RunLoop 时会先指定一个 Mode ,检查指定 Mode 是否存在以及 Mode 中是否含有 SourceTimer ,如果 Mode 不存在或者 Mode 中无 SourceTimer ,认为该 Mode 是一个空的 ModeRunLoop 就直接退出。

Input Source:

  • Port-Based Sources:监听 AppMach Port ,由内核发出信号,输入源收到信号后,执行相关的例程。

  • Custom Input Sources:监听自定义的输入源,需要在其它线程手动发送信号,输入源收到信号后,执行相关的例程。

  • Cocoa Perform Selector Sources: Cocoa 中自定义的输入源,目的是在不同线程中执行任务,同一线程中的任务是顺序执行的,当任务执行完成后系统会自动移除这个源。( 注意:在目标线程中执行任务时,这个目标线程必须有活跃的RunLoop

Timer Source:

时间源会在预设的时间同步传递事件给对应的线程,计时器是线程通知自己做某事的一种方式。

计时器并不是真正的实时的,当计时器未处于 RunLoop 当前监听的 Mode ,那么计时器是不会计时调度任务的,只有 RunLoop 当前监听的 Mode 是计时器关联的 Mode 时,计时器才会开始执行任务,例如: NSTimer 添加至主线程 RunLoopDefaultMode 中,此时滑动 TableView / ScrollView 时, RunLoop 会切换至 TrackMode ,计时器是不会调度任务的。

如果 RunLoop 在执行一个例程时,计时器触发了,那么计时器会等待 RunLoop 将该例程执行完成,在下一次的循环中处理。在 RunLoop 未运行情况下,计时器永远不会触发任务。

二、RunLoop怎么使用?

应用启动时,会自动在主线程上设置运行 RunLoop ,所以不需要在主线程上显示的启动 RunLoop ,无需调用 [[NSRunLoop currentRunLoop] runUntilDate:] 这些方法。那么如果我们显示的在主线程中调用 RunLooprun 方法会出现什么结果呢?通过 Demo 中显示,主线程中显示启动 RunLoop 会影响当前事件处理,但是由于 RunLoop 并没有停止,所以其他事件能够正常接收和处理。

而子线程也不并是必须要设置运行 RunLoop 才能执行任务,比如说只是简单在子线程中处理个耗时任务等,如下场景是需要启动 RunLoop 的:

  1. 使用 NSPort 或者自定义输入源与其它线程通信。
  2. 在线程上使用计时器。
  3. 在一个 Cocoa 应用中使用 performSelector 相关方法。
  4. 使线程常驻,在该线程定期执行任务。

正如前言中所说,本文主要说明线程常驻和自定义输入源线程通信。

线程常驻:

方式一:无条件的启动 RunLoop 是最简单的选择,但它也是最不可取的选择,它会将线程置于永久循环中,这样几乎无法控制 RunLoop 本身,虽然可以添加和删除输入源和计时器,但停止 RunLoop 的唯一方法是杀死 RunLoop 。(以上内容是通过Google翻译的官网内容可能理解有些偏差届时还望指正,事实上我在做实验的过程中,发现使用 NSThreadcancel 方法是无法停止 RunLoop 的, cancel 方法是更改线程的取消状态,指示它应该退出。在当前线程下执行 [NSThread exit] 方法,退出了该线程,但 demo 中的 LongLifeThreadViewController 仍然未被释放)

方式二:启动 RunLoop 时设定时限, RunLoop 将一直运行直到事件到达或分配的时间到期。如果事件到达,则将该事件分派给处理程序进行处理,然后退出此次 RunLoop 。可以通过重新启动 RunLoop 处理下一个事件。同样如果分配的时间到期,也可以重新启动 RunLoop 来处理。这种方式可以指定 RunLoopMode ,官网力荐。

自定义输入源线程通信:

定义输入源:

RunLoop

个人感觉可以根据个人需求决定是否实现第3、4两条内容。(注意定义输入源只能通过CoreFoundation提供的对应API实现,其中的回调例程由C语言实现)

RunLoop 上安装输入源:如果实现了上述的第3条内容时,将自定义的输入源添加到 RunLoop 时,就会回调输入源对应的 schedule 实现例程。

向输入源发送信号:输入源在接收到信号后,会执行对应的 perform 例程, perform 例程就是对应事件处理程序。(注意如果线程处于休眠状态,要唤醒线程,否则该事件无法被处理。

结语:

关于 RunLoop 的内容还有很多,比如: RunLoopModesRunLoopObserverNSPortNSTimer 等等,当然还有 RunLoop 的源码,这些内容在此并未列出,如有感兴趣的小伙伴可以先行花时间去探索、学习,到时可以一起交流、讨论。

分享给小伙伴们:
本文标签: iOSRunLoop

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.