RunLoop备忘

107 阅读2分钟

什么是 RunLoop

  • 应用范畴

    • 定时器、PerformSelector
    • GCD Async Main Queue
    • 事件响应、手势识别、界面刷新
    • 网络请求
    • AutoreleasePool
  • RunLoop的基本作用

    • 保持程序的持续运行
    • 处理 App 中的各种事件
    • 节省CPU资源,提高程序性能:该做事时做事,该休息时休息

RunLoop对象

NSRunLoop 是基于 CFRunLoopRef 的一层 OC 包装

RunLoop与线程

  • 每条线程都有唯一的一个与之对应的 RunLoop对象
  • RunLoop 保存在一个全局的 Dictionary里,线程作为 key,RunLoop 作为 value
  • 线程刚创建时并没有 RunLoop对象,RunLoop 会在第一次获取它时创建
  • RunLoop会在线程结束时销毁
  • 主线程 RunLoop 自动获取,子线程默认没有开启 RunLoop(这个就是你在子线程只开启runloop他仍然会退出的原因)

RunLoop相关的类

  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef
struct __CFRunLoop {
    pthread_t _pthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
}

struct __CFRunLoopMode {
    CFStringRef _name;
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
}

CFRunLoopModeRef

  • CFRunLoopModeRef 代表 RunLoop 的运行模式
  • 一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source0/Source1/Timer/Observer
  • RunLoop启动时只能选择其中一个 Mode,作为 currentMode
  • 如果需要切换Mode,只能退出当前 Loop,再重新选择一个 Mode 进入,不同组的Source0/Source1/Timer/Observer能分隔开,互不影响
  • 如果 Mode 里没有任何 Source0/Source1/Timer/Observer,RunLoop会立马退出
  • 常见的两种 Mode
    • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App默认的Mode,通常主线程是在这个Mode下运行
    • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode影响

RunLoop的运行逻辑

  • Source0

    • 触摸事件处理
    • performSelector:onThread:
  • Source1

    • 基于 Port 的线程间通信
    • 系统事件的捕捉
  • Timers

    • NSTimer
    • performSelector:withObject:afterDelay:
  • Observers

    • 用于监听 RunLoop 的状态
    • UI刷新(BeforeWaiting)
    • AutoreleasePool(BeforeWaiting)

休眠的细节

用户态调用mach_msg(),就会切换到内核态去真正执行mach_msg(),让线程等待消息(没有消息让线程休眠,有消息就唤醒线程)

线程保活

[[NSRunLoop currentRunLoop] run]是无法停止的,它专门用于开启一个永不销毁的线程(NSRunLoop)

RunLoop内部实现的逻辑