关于UIImage.prepareForDisplay工作原理及未使用decodedImage仍能优化性能的技术疑问
关于UIImage.prepareForDisplay工作原理及未使用decodedImage仍能优化性能的技术疑问
嘿,我来帮你拆解这个问题,先搞懂prepareForDisplay到底在做什么,再解释你遇到的两个奇怪现象~
先搞懂为什么原来的代码会卡顿
你之前用UIImage(contentsOfFile: url)加载图片时,其实只是把磁盘上的压缩图片数据(比如JPEG/PNG的二进制)读进了内存,但真正的像素解码工作是在图片第一次显示到屏幕上的时候,在主线程完成的。当你加载大量图片时,主线程被密集的解码任务占满,自然就会出现严重卡顿。
prepareForDisplay到底在干吗?
prepareForDisplay的核心作用就是把解码工作从主线程移到后台异步执行:
- 它会在后台线程将压缩的图片数据解码成适合当前屏幕的像素格式(比如匹配屏幕分辨率、色彩空间),这个过程完全不占用主线程,所以你的App卡顿问题就解决了。
- 解码完成后,它会通过闭包返回一个优化后的
decodedImage实例,同时还会把原始uiImage的解码结果缓存起来——这就是你没用到decodedImage但性能依然变好的关键!
为什么没用到decodedImage还能优化性能?
你没看错,即使你不使用闭包里的decodedImage,原始的uiImage也已经被“预热”过了:
- 当你调用
uiImage.prepareForDisplay时,后台解码过程不仅生成了decodedImage,还会把解码后的像素数据缓存到原始的uiImage对象中。 - 等你在主线程设置
self.image = uiImage时,系统直接就能用已经解码好的像素数据,不用再在主线程做解码工作了,自然就不会卡顿。
关于decodedImage报错的问题
你遇到的[Decompressor] Error -17102一般有这几个原因:
- 图片本身可能有损坏,或者格式不被
prepareForDisplay的解码器支持; decodedImage是闭包内的临时对象,如果在闭包外引用它,可能会因为生命周期问题被提前释放,导致解码失败;- 另外,
prepareForDisplay返回的decodedImage是适配当前屏幕的优化版本,有些特殊图片(比如带Alpha通道的WebP、或者高分辨率的RAW图)可能在解码时出现兼容性问题。
给你一个更规范的写法建议
虽然你现在的代码能工作,但更稳妥的方式是利用好decodedImage,同时做安全判断:
uiImage.prepareForDisplay { decodedImage in DispatchQueue.main.async { // 优先用解码后的优化图片,解码失败则 fallback 到原始图片 self.image = decodedImage ?? uiImage } }
这样既能保证性能优化,又能避免解码失败时出现空白或者报错的情况。
备注:内容来源于stack exchange,提问作者WinterSoldier
相关产品推荐
相关产品推荐

