# XCFPSMonitor **Repository Path**: xchaun/xcfpsmonitor ## Basic Information - **Project Name**: XCFPSMonitor - **Description**: FPS监控 - **Primary Language**: Swift - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-02-17 - **Last Updated**: 2026-03-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # XCFPSMonitor #### 介绍 FPS监控,主线程卡顿监控 #### 安装教程 `pod XCFPSMonitor` ### 实现思路 - CADisplayLink 默认每秒 60次; - 将 CADisplayLink add 到 mainRunLoop 中; - 使用 CADisplayLink 的 timestamp 属性,在 CADisplayLink 每次 tick 时,记录上一次的 timestamp; - 用 _count 记录 CADisplayLink tick 的执行次数; - 计算此次 tick 时, CADisplayLink 的当前 timestamp 和 _lastTimeStamp 的差值; - 如果差值大于1,fps = _count / delta,计算得出 FPS 数 ### 问题一: UIScrollView 在滑动时,timer 会被暂停的问题 - 原因:runloop mode 导致。iOS处理滑动时,mainloop 中UIScrollView 的 mode 是 UITrackingRunLoopMode,会优先保证界面流畅,而 timer 默认的 model是 NSDefaultRunLoopMode,所以会出现被暂停。 - 解决办法:将 timer 加到 NSRunLoopCommonModes 中。 ### 问题二:NSTimer 对于 target 的循环引用问题: ``` CADisplayLink *_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)]; [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(tick:) userInfo:nil repeats:YES]; ``` 原因:以上两种用法,都会对 self 强引用,此时 timer持有 self,self 也持有 timer,循环引用导致页面 dismiss 时,双方都无法释放,造成循环引用。此时使用 __weak 也不能有效解决: 解决办法1:在页面退出前,或者合适的时候,手动停止 timer,结束循环引用。注意:在 dealloc 方法中是肯定不行的!由于循环引用,dealloc 方法不会调用。所以在onDisappear方法中关闭定时器Timer ### 2.主线程卡顿监控 我们可以添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的 实现思路: 在整个运行循环中,需要监听的主要就是RunLoop结束休眠到处理Source0的这段时间,如果时间过长,就证明有耗时操作 检测主线程每次执行消息循环的时间,当这个时间大于规定的阈值时,就记为发生了一次卡顿。这个也是微信卡顿三方matrix的原理