iOS RunLoop 总结以及相关面试题解答

Runloop

Runloop是事件接收和分发机制的一个实现。是线程相关的基础框架的一部分。一个Runloop就是一个事件处理的循环,用来不停的调度工做及处理输入事件。使用runloop的目的就是让你的线程面试

RunLoop的主要目的安全

保证程序执行的线程不会被系统终止,若是没有RunLoop,UIApplicationMain函数执行完毕以后将直接返回,就是说程序一启动而后就结束,在有工做的时候忙于工做,而没有工做的时候处于休眠状态,bash

何时使用Runloop框架

当须要和该线程进行交互的时候才会使用Runloop函数

Runloop Mode

一个Runloop可能有几个modeoop

Runloop Mode 其实是 SourceTimerObserver 的集合,不一样的 Mode 把不一样组的 SourceTimerObserver 隔绝开来。Runloop 在某个时刻只能跑在一个 Mode 下,处理这一个 Mode 当中的 Source,Timer 和 Observer。优化

苹果文档中提到的 Mode 有五个,分别是:spa

  • NSDefaultRunLoopMode:默认的mode,正常状况下都是在这个mode线程

  • NSConnectionReplyMode指针

  • NSModalPanelRunLoopMode

  • NSEventTrackingRunLoopMode:使用这个Mode去跟踪来自用户交互的事件(好比UITableView上下滑动)

  • NSRunLoopCommonModes

iOS 中公开暴露出来的只有 NSDefaultRunLoopModeNSRunLoopCommonModesNSRunLoopCommonModes 其实是一个 Mode 的集合,默认包括 NSDefaultRunLoopModeNSEventTrackingRunLoopMode

Source

便可以唤醒Runloop的一些事件。好比用户点击了屏幕,就会建立一个input source。

  • source0 : 非系统事件

只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你须要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,而后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。

  • source1 : 系统事件

包含了一个 mach_port和一个回调(函数指针),被用于经过内核和其余线程相互发送消息。这种 Source 能主动唤醒 RunLoop 的线程

Timer

咱们常常用的NSTimer就属于这一类。

Observer

某个observer能够监听runloop的状态变化,并做出必定反应。

RunLoop运行流程

经典大图

没有事情的时候,Runloop处于休眠状态。当外部source将其唤醒后,它会依次处理接收到的timer/source,而后再次进入休眠。

常见的面试题:

Runloop和线程是什么关系?

每条线程都有惟一的一个与之对应的RunLoop对象,其关系是保存在一个全局的 Dictionary 里;主线程的RunLoop已经自动建立,子线程的RunLoop须要主动建立;RunLoop在第一次获取时建立,在线程结束时销毁

Runloop的mode做用是什么?

指定事件在运行循环中的优先级的,

线程的运行须要不一样的模式,去响应各类不一样的事件,去处理不一样情境模式。(好比能够优化tableview的时候能够设置UITrackingRunLoopMode下不进行一些操做,好比设置图片等。)

+scheduledTimerWithTimeInterval:的方式触发的timer,在滑动页面上的列表时,timer会暂停回调, 为何?

滑动scrollView时,主线程的RunLoop会切换到UITrackingRunLoopMode这个Mode,执行的也是UITrackingRunLoopMode下的任务(Mode中的item),而timer是添加在NSDefaultRunLoopMode下的,因此timer任务并不会执行,只有当UITrackingRunLoopMode的任务执行完毕,runloop切换到NSDefaultRunLoopMode后,才会继续执行timer。

如何解决在滑动页面上的列表时,timer会暂停回调?

Timer放到NSRunLoopCommonModes中执行便可

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
复制代码

NSTImer使用时须要注意什么?

  • 注意timer添加到runloop时应该设置为何mode
  • 注意timer在不须要时,必定要调用invalidate方法使定时器失效,不然得不到释放

RunLoop 有哪些应用?

常驻内存、AutoreleasePool 自动释放池

AutoreleasePoolRunLoop 有什么联系?

iOS应用启动后会注册两个 Observer 管理和维护 AutoreleasePool。应用程序刚刚启动时默认注册了不少个Observer,其中有两个Observer的 callout 都是 _ wrapRunLoopWithAutoreleasePoolHandler,这两个是和自动释放池相关的两个监听。

  • 第一个 Observer 会监听 RunLoop 的进入,它会回调objc_autoreleasePoolPush() 向当前的 AutoreleasePoolPage 增长一个哨兵对象标志建立自动释放池。这个 Observer 的 order 是 -2147483647 优先级最高,确保发生在全部回调操做以前。

  • 第二个 Observer 会监听 RunLoop 的进入休眠和即将退出 RunLoop 两种状态,在即将进入休眠时会调用 objc_autoreleasePoolPop() 和 objc_autoreleasePoolPush() 根据状况从最新加入的对象一直往前清理直到遇到哨兵对象。而在即将退出 RunLoop 时会调用objc_autoreleasePoolPop() 释放自动自动释放池内对象。这个Observer 的 order 是 2147483647 ,优先级最低,确保发生在全部回调操做以后。

NSRunLoop 和 CFRunLoopRef 区别

CFRunLoopRef 基于C 线程安全,NSRunLoop 基于 CFRunLoopRef 面向对象的API 是不安全的

备注

因为做者水平有限,不免出现纰漏,若有问题还请不吝赐教。

相关文章
相关标签/搜索