CFRunloopObserver
CFRunloopObserver 定义
struct __CFRunloopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
结论:
1. 一个 observer 只能观察一个 runloop
2. 一个 observer 可以观察多个 runloop 状态
CFRunloopObserver 功能
CFRunloopObserver 观察 runloop 的各种状态,并抛出回调。
runloop 有6种状态
- 即将进入 runloop
- 即将处理 timer
- 即将处理 source
- 即将进入睡眠
- 即将唤醒(X) (被唤醒但是还没开始处理事件)
- 即将退出 runloop(X)(runloop已经退出)
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), //即将进入run loop
kCFRunLoopBeforeTimers = (1UL << 1), //即将处理timer
kCFRunLoopBeforeSources = (1UL << 2),//即将处理source
kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6),//被唤醒但是还没开始处理事件
kCFRunLoopExit = (1UL << 7),//run loop已经退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
CFRunloopObserver 应用
-
AutoreleasePool
应用启动后,程序会注册两个 Observer 观察:_wrapRunLoopWithAutoreleasePoolHandler- 即将进入 runloop(调用 objc_autoreleasePoolPush() 为当前 page 添加哨兵对象)
- 即将进入睡眠(先调用 objc_autoreleasePoolPop() release autorelease 对象,再调用 objc_autoreleasePoolPush() 为当前 page 添加新的哨兵对象),退出 runloop(调用 objc_autoreleasePoolPop() 释放自动释放池)。
-
UI绘制
应用启动后,程序会注册一个 Observer 观察:_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv- 即将进入睡眠。当 views 的 frame 发生改变,或视图的层级发生变化时等,这些 view 会被标记为待处理,并被加入到一个全局的容器中,当 runloop 即将进入睡眠时,回调这个 observer 回调,查找有没有需要更新的 views,若有则进行绘制。(所以当 view.frame 发生变化时,会在下一个 runloop 周期内绘制)
-
手势识别
苹果注册了一个 observer 观察:_UIGestureRecognizerUpdateObserver()- 即将进入睡眠。当用户触摸屏幕时,首先 IOKit.framework 会产生一个 IOHIDEvent 事件,并由 springboard 接收。springboard 通过 mach port 转发给应用进程,触发 runloop 的 source1 回调,并调用 _UIApplicationHandleEventQueue() 进行应用内部分发。_UIApplicationHandleEventQueue() 若识别这是一个手势,首先会调用 cancel 将当前的 touchesBegin/Move/End 回调打断。随后系统将对应的 UIGestureRecognize 标记为待处理。runloop 即将进入睡眠时,获取所有待处理的 gesture,并执行其回调。