通过对上图中 blraa 指令 step in , 我们发现这个 block 实际上是由 UIKitCore 注册的:
找到引用了该符号的 UIKit 的私有方法 __UIUpdateCycleSchedulerStart ,反汇编结果也验证了这点 。
同时发现这个 block 的返回值固定为 0x0 。
而同样的 symbol 在之前的 iOS 版本上并不存在,也就是说这个应该是 iOS 15 的变动 。换安装了 iOS 15 的非 ProMotion 设备,重走上面的逆向流程发现,该设备的 CA::display_link_will_fire_handler 为 nil,未注册:
这里 cbz 执行了跳转 , 说明 x0 为 nil,而 x0 是由 ldr x0, [x8, #0x1c8] 得到 。
可以看到 x0 就是 CA::display_link_will_fire_handler 。继续分析之前找到的私有符号 __UIUpdateCycleSchedulerStart 的相关实现,可以知道这是因为在非 ProMotion 设备上 _UIUpdateCycleEnabled 返回了 NO 导致的 。
在返回 NO 的情况下 __UIUpdateCycleSchedulerStart 方法不会执行,CA::display_link_will_fire_handler 也就不会被注册 。
_UIUpdateCycleEnabled 所带来的变化继续研究 _UIUpdateCycleEnabled 相关的代码,笔者发现这个的改动并不是仅仅影响 DisplayLink 驱动方式那么简单 。
当 _UIUpdateCycleEnabled 返回 YES 时,UIKit 会在 UIApplicationMain 中执行 _UIUpdateCycleSchedulerStart 。分析该函数,发现 _UIUpdateCycleEnabled 启用时会调用 [CATransaction setDisableRunLoopObserverCommits:YES] 。
Core Animation 是绝大部分 iOS 应用的渲染引擎 , 熟悉 iOS 渲染流程的同学想必都知道它的执行也是由 MainRunLoop 驱动 , 大致为:
MainRunLoop 因为用户操作/Timer/GCD 等被唤醒,派发相应的事件/回调回调中应用修改 Layer Tree,触发 setNeedsLayout 或 setNeedsDisplayMainRunLoop 即将完成本次执行 , 在即将休眠前向 Observer 派发 BeforeWaiting 事件BeforeWaiting 中触发 Core Animation 注册的 MainRunLoop Observer,触发事务提交 CA::Transaction::commit():自顶向下触发各种 Layout/Display 等逻辑,更新布局/内容Core Animation 将更新后的 Layer Tree 打包发送给 Render Server5.随后 MainRunLoop 进入休眠
6.Render Server 将打包好的 Layer Tree 解码,生成并提交对应的 draw calls
7.GPU 执行渲染指令 , 渲染出 FrameBuffer , 待后续 VSync 信号来临时上屏展示
上图中 +[CATransaction setDisableRunLoopObserverCommits:YES] 这个调用给了笔者提示 , 让我们验证一下 CA::Transaction::commit() 在 iOS 15 ProMotion 设备上的执行时机 , 会发现确实不再由 BeforeWaiting 事件驱动了:
实际上同样的 Source 0 信号同时也驱动了 CADisplayLink 的回调:
关注这个 Source 0 的回调符号 runloopSourceCallback,会发现这个 Source0 是由 signalChanges 函数驱动:
推荐阅读
- 小米手机怎么查看本机号码显示未知 小米手机怎么查看本机号码
- 小米9网络不好怎么办
- 锂电池电动车怎样充电更耐用 锂电池电动车怎样充电更耐用些
- 小米手机在哪调屏幕亮时间 小米手机怎么调屏幕亮的时间
- bf3电池是vivo什么型号的手机,vivo电池型号b_f3是哪个型号手机
- 雅迪石墨烯电池正确充电方法 雅迪石墨烯电池正确充电方法图片
- 12ah电池能跑多远 60v12ah电池能跑多远
- 小米新旗舰双11降价:首批澎湃OS+4nm旗舰芯+IP68,不到2500拿下
- 捡来的手环怎样恢复出厂设置 小米手环3怎么恢复出厂设置
- 小米note3清除数据 红米note3怎么清除数据