RunLoop

  • 概念
  • 数据结构
  • 事件循环机制
  • RunLoop 与 NSTimer
  • RunLoop 与多线程

一、概念

  • RunLoop是通过内部维护的事件循环对事件/消息进行管理的一个对象

事件循环:

  • 没有消息需要处理时,休眠以避免资源占用(用户态--> 内核态)
  • 有消息需要处理,立刻被唤醒(内核态 --> 用户态)
系统调用相关指令如开关机等是在内核态的,程序一般运行在用户态的,绝大部分API都是用户态的
image

二、数据结构

NSRunLoop 是 CFRunLoop 的封装,提供了面相对象的API,其数据结构如下:

  • CFRunLoop
  • CFRunLoopMode
  • Source/Timer/Observer

1、CFRunLoop

包含以下内容:

  • pthread --- (RunLoop和线程一一对应)
  • currentMode --- CFRunLoopMode
  • modes --- NSMutableSet
  • commonModes --- NSMutableSet
  • commonModeItems --- 也是一个集合,包含多个 Observer(观察者)、Timer、Source

2、CFRunLoopMode

  • name --- 名称,如 NSDefaultRunLoopMode 等
  • sources0 -- 集合类型,无序的
  • sources1 --- 集合类型
  • observers --- 数组,有序的
  • timers --- 数组

3、CFRunLoopSource

  • source0 --- 需要手动唤醒线程
  • source1 --- 具备唤醒线程的能力

4、CFRunLoopTimer

  • 基于事件的定时器,和 NSTimer 是 toll-free bridged的。(即可以桥转换)

5、CFRunLoopObserver

观测时间点:

  • kCFRunLoopEntry
  • kCFRunLoopBeforeTimers
  • kCFRunLoopBeforeSources
  • kCFRunLoopBeforeWaiting --- 即将休眠,即将切换内核状态
  • kCFRunLoopAfterWaiting --- 内核态切换到用户态不久之后发出
  • kCFRunLoopExit

各个数据结构之间的关系

一对多的关系:


image

RunLoop的Mode:

问题:怎样将Timer同时添加到两个mode?以保证mode切换的时候,不影响timer的使用
image
解决 :NSRunLoopCommonModes
NSRunLoopCommonModes的特殊性
  • commonMode 不是实际存在的一种Mode
  • 是同步 Source/Timer/Observer 到多个 Mode 中的一种技术方案

三、事件循环机制

image
APP运行生命周期内RunLoop的整体事件循环机制

RunLoop的核心

image

四、RunLoop 与 NSTimer

问题:滑动 TableView 时,定时器还会生效吗?
回答:不会生效,timer 默认加入到 defaultMode 中,滑动的时候,Mode 会从 kCFRunLoopDefaultMode 切换到 UITrackingRunLoopMode,不同的 Mode ,timer 不相关,所以不生效
解决:添加到 kCFRunLoopCommonMode 中

五、RunLoop 与多线程

  • 线程是和 RunLoop 一一对应的
  • 自己创建的线程默认是没有 RunLoop 的

怎样实现一个常驻线程

  • 为当前线程开启一个 RunLoop
  • 向该 RunLoop 中添加一个 Port/Source 等维持 RunLoop 的事件循环
  • 启动该 RunLoop

代码实现:

运行的模式和资源添加的模式一定要是同一个
image

image

总结

  • 什么是 RunLoop ,是怎样做到有事做事,没事休息的?
  • RunLoop 与线程的关系?
  • 如何实现常驻线程?
  • 怎样保证子线程数据回来更新UI的时候,不打断用户的滑动操作?(把子线程抛给主线程的操作添加到 DefaultMode 下,此时滑动 UITrackingRunLoopMode 不受影响)

你可能感兴趣的:(RunLoop)