建筑师之家IOS / NOTES
← 全部笔记

性能

图片的内存按像素算

文件只有几百 KB,解码后仍可能是几十 MB。要降的是解码尺寸,不是再压一遍 JPEG。

一张 4032×3024 的照片,文件可能 2MB。解码成 bitmap 大约是宽 × 高 × 4 字节,也就是 48MB 上下。界面上只显示 120 点的头像,却把整张图交给 UIImageView,内存和主线程解码都会爆。列表里再来二十张,jetsam 的原因就很清楚了。

按目标尺寸解码

用 ImageIO 在解码时就限制最大边,而不是先 UIImage(contentsOfFile:) 再画到小上下文里。后一种仍然会先把大图展开。

import ImageIO
import UIKit

func thumbnail(at url: URL, maxPixel: Int) -> UIImage? {
    let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    guard let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions) else {
        return nil
    }
    let options = [
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: true,
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxPixel
    ] as CFDictionary
    guard let image = CGImageSourceCreateThumbnailAtIndex(source, 0, options) else {
        return nil
    }
    return UIImage(cgImage: image)
}

maxPixel 用点尺寸乘以屏幕 scale。120pt 的格子在 3x 上是 360 像素,没有必要解到 1000。方向要用 CreateThumbnailWithTransform,否则手机拍的竖图会歪。

缓存存什么

滚动时取消离开屏幕的解码任务。prepareForReuse 里把 image 置空,并取消对应的 Task。不然复用到下一行时,上一行的大图还会写回来,既闪又占内存。

Asset Catalog 里的矢量图和 PDF 要看保留矢量还是栅格化。大面积拉伸的矢量在主线程上重新渲染,列表里一样会卡。图标小、张数少,矢量合适;复杂插画,导出固定倍率的位图更稳。