UITableView 卡顿排查记实

前言

项目中实现了一个歌曲列表,Cell 的内容是歌曲封面和标题的简单内容,但是在滑动时会出现卡顿,本文记录下排查过程。

使用 Instruments

对于卡顿掉帧问题大多数都是在主线程进行了较大的耗时操作,所以使用 Instruments 中 Time Profile 来检测下具体是什么方法耗时较长。

可以看到在 Runloop 的回调中执行了 CA::Transaction::commit(),之后调用了 ImageIO 框架进行图片的解码。那么问题来了,为什么加载其他图片不会?这里执行解码的类是 PNGReadPlugin,会不会是 PNG 图片解码就会卡顿?

查看源码

objc 复制代码
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
    // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
    if (image == nil) {
        return NO;
    }
    
    // do not decode animated images
    if (image.images != nil) {
        return NO;
    }
    
    CGImageRef imageRef = image.CGImage;
    
    BOOL hasAlpha = SDCGImageRefContainsAlpha(imageRef);
    // do not decode images with alpha
    if (hasAlpha) {
        return NO;
    }
    
    return YES;
}

经过一番查找,找到了这段关键代码。可以看到,这里判断了图片是否包含 Alpha 通道,如果包含则不进行解码。所以刚才的猜测是正确的,PNG 图片会包含 Alpha 通道,SDWebImage 不会对其进行解码,造成了卡顿。

之前对于文章《iOS 处理图片的一些小 Tip》中提到的"UIImage 第一次显示到屏幕时才会被解码"不太理解,这次算是遇上了。

解决方案

升级 SDWebImage

由于一些历史原因,项目中使用的 SDWebImage 版本还是比较老的 4.2.3 版本,而最新版本的 SDWebImage 已经支持对包含 alpha 通道的 PNG 图片进行解码

objc 复制代码
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
    // Avoid extra decode
    if (image.sd_isDecoded) {
        return NO;
    }
    // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
    if (image == nil) {
        return NO;
    }
    // do not decode animated images
    if (image.images != nil) {
        return NO;
    }

    return YES;
}

服务端裁剪成小图

造成卡顿的另一个原因是直接使用了原图,分辨率较大,可以通过在图片 URL 上拼接相关参数获取一张小图,这个方案有诸多优点:

  • 显示效果更佳
  • 节省用户流量
  • 提高加载速度

延伸思考

NSData 转化成 UIImage 不是就完成解码了吗?

SDWebImage 的解码做了什么,和系统 ImageIO 的解码有什么不同?

系统为什么要把图片解码这么耗时的操作放到主线程?

带着这些疑问找到 SDWebImage 的主要维护作者的文章 主流图片加载库所使用的预解码究竟干了什么,解答了我的所有疑惑。

这里简单总结一下:

  • NSData 转化成 UIImage 之后,它的 Bitmap 是没有立即创建的,这个 UIImage 只是包含一些元信息的空壳,等到最终显示到屏幕上才会创建。
  • SDWebImage 等第三方库通过在子线程调用 CGContextDrawImage让 ImageIO 立即解码分配 Bitmap 内存。
  • iOS 早期设备的内存非常有限,所有图片都提前进行解码会增加内存的压力。
相关推荐
tiantian_cool15 小时前
Claude Code 四大核心技能使用指南
ios
冰淇淋真好吃18 小时前
iOS实现 WKWebView 长截图的优雅方案
ios
前端不太难1 天前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios
搜狐技术产品小编20232 天前
精通 UITableViewDiffableDataSource——从入门到重构的现代 iOS 列表开发指南
ios·重构
tangweiguo030519872 天前
SwiftUI 状态管理完全指南:从 @State 到 @EnvironmentObject
ios
Digitally2 天前
如何轻松地将文件从 PC 传输到 iPhone
ios·iphone
iosTiov2 天前
当IPA遇见信任:解密ios生态中“签名”的真正力量
ios·团队开发·苹果签名·稳定
游戏开发爱好者82 天前
如何使用 AppUploader 提交上传 iOS 应用
android·ios·小程序·https·uni-app·iphone·webview
和沐阳学逆向2 天前
iOS 18 越狱教程:palera1n + 巨魔安装全流程
ios·巨魔商店·ios越狱·ios18越狱
ii_best3 天前
安卓/ios脚本开发辅助工具按键精灵横纵坐标转换教程
android·开发语言·ios·安卓