UI 卡顿排查
问题
App 滑动列表时卡顿掉帧,如何排查和优化?
答案
排查步骤
常见原因及优化
| 原因 | 排查方式 | 优化方案 |
|---|---|---|
| 离屏渲染 | 模拟器 → Color Off-screen Rendered | 避免 cornerRadius + masksToBounds |
| 图片解码 | Time Profiler 看 CGImageSourceCreateImageAtIndex | 后台线程预解码 |
| AutoLayout 嵌套过深 | Layout 阶段耗时 | 减少嵌套或用手动布局 |
| 透明混合 | Color Blended Layers | 设置 isOpaque = true,避免透明背景 |
| 主线程 I/O | 主线程出现文件/数据库调用 | 移到后台线程 |
离屏渲染优化
// ❌ 触发离屏渲染
imageView.layer.cornerRadius = 8
imageView.layer.masksToBounds = true
// ✅ 方案一:使用 CAShapeLayer 遮罩
let mask = CAShapeLayer()
mask.path = UIBezierPath(roundedRect: imageView.bounds, cornerRadius: 8).cgPath
imageView.layer.mask = mask
// ✅ 方案二:后台线程绘制圆角图片
extension UIImage {
func roundedImage(radius: CGFloat) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { ctx in
UIBezierPath(roundedRect: CGRect(origin: .zero, size: size), cornerRadius: radius).addClip()
draw(in: CGRect(origin: .zero, size: size))
}
}
}
常见面试问题
Q1: 如何在线上检测卡顿?
答案:子线程定时向主线程发信号量,如果超时(>50ms)说明主线程阻塞。此时采集主线程调用栈上报。这是 卡顿监控 的核心原理。