iOS开发——有关RunLoop

深入理解RunLoop

一篇很深入很深入的博文:深入理解RunLoop

苹果利用 RunLoop 实现自动释放池、延迟回调、触摸事件、屏幕刷新等功能的。

RunLoop 的概念

RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行Event Loop 的逻辑(让线程能随时处理事件但并不退出,在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒)

RunLoop 与线程的关系

CFRunLoop 是基于 pthread 来管理的
线程和 RunLoop 之间是一一对应的,线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。

RunLoop 对外的接口

在 CoreFoundation 里面关于 RunLoop 有5个类:

  • CFRunLoopRef
  • CFRunLoopModeRef(没有暴露)
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef

RunLoop 的 Mode

你只能通过 mode name 来操作内部的 mode,当你传入一个新的 mode name 但 RunLoop 内部没有对应 mode 时,RunLoop会自动帮你创建对应的 CFRunLoopModeRef。对于一个 RunLoop 来说,其内部的 mode 只能增加不能删除。

一个 item 可以被同时加入多个 mode。但一个 item 被重复加入同一个 mode 时是不会有效果的。如果一个 mode 中一个 item 都没有,则 RunLoop 会直接退出,不进入循环。

RunLoop 的内部逻辑

iOS开发——有关RunLoop_第1张图片

CFRunLoopSourceRef 是事件产生的地方。Source有两个版本:Source0 和 Source1。

  • Source0 只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。
  • Source1 包含了一个 mach_port 和一个回调(函数指针),被用于通过内核和其他线程相互发送消息。这种 Source 能主动唤醒 RunLoop 的线程。

实际上 RunLoop 就是这样一个函数,其内部是一个 do-while 循环

RunLoop 的底层实现

  • RunLoop 的核心是基于 mach port 的
  • RunLoop 的核心就是一个 mach_msg()

苹果用 RunLoop 实现的功能

  • AutoreleasePool
    App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,一个监听回调释放池创建push,一个监听回调释放池释放pop
  • 事件响应
  • 手势识别
  • 界面更新
  • 定时器
  • PerformSelecter
  • 关于GCD:dispatch_async()
  • 网络请求

    AFNetwork: NSURLConnection传输网络时,内部使用RunLoop 来接收底层 socket 的事件,并通过之前添加的 Source0 通知到上层的 Delegate。

  • AsyncDisplayKit

ASDK 仿照 QuartzCore/UIKit 框架的模式,实现了一套类似的界面更新的机制:后台线程更改。即在主线程的 RunLoop 中添加一个 Observer,监听了 kCFRunLoopBeforeWaiting 和 kCFRunLoopExit 事件,在收到回调时,遍历所有之前放入队列的待处理的任务,然后一一执行。

你可能感兴趣的:(iOS)