10. 图片优化
图片是性能瓶颈的高发区,核心问题是:解码成本、内存占用、重复加载。下面按链路拆开处理。
一、缩略图与下采样
import ImageIO
func downsample(data: Data, to size: CGSize, scale: CGFloat) -> UIImage? {
let options = [kCGImageSourceShouldCache: false] as CFDictionary
guard let source = CGImageSourceCreateWithData(data as CFData, options) else { return nil }
let maxDimension = max(size.width, size.height) * scale
let downsampleOptions = [
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceShouldCacheImmediately: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: maxDimension
] as CFDictionary
guard let image = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else { return nil }
return UIImage(cgImage: image)
}
二、解码放到后台线程
DispatchQueue.global().async {
let image = UIImage(data: data)
DispatchQueue.main.async {
imageView.image = image
}
}
三、内存缓存
final class ImageCache {
static let shared = ImageCache()
private let cache = NSCache<NSString, UIImage>()
func get(_ key: String) -> UIImage? { cache.object(forKey: key as NSString) }
func set(_ image: UIImage, key: String) { cache.setObject(image, forKey: key as NSString) }
}
四、磁盘缓存
final class DiskCache {
private let folder: URL
init(folderName: String) {
let base = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
folder = base.appendingPathComponent(folderName)
try? FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
}
func save(_ data: Data, key: String) throws {
try data.write(to: folder.appendingPathComponent(key), options: .atomic)
}
func load(key: String) -> Data? {
try? Data(contentsOf: folder.appendingPathComponent(key))
}
}
五、列表预加载
extension FeedVC: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
let urls = indexPaths.compactMap { items[$0.row].coverURL }
urls.forEach { loadImage(url: $0) }
}
}
六、避免离屏渲染
- 圆角 + 阴影容易触发离屏
- 尽量设置
shadowPath - 大量图片尽量用圆角图片资源或预处理
imageView.layer.cornerRadius = 8
imageView.layer.masksToBounds = true
七、URLCache 与网络缓存
let cache = URLCache(memoryCapacity: 20 * 1024 * 1024,
diskCapacity: 100 * 1024 * 1024,
diskPath: "image-cache")
let config = URLSessionConfiguration.default
config.urlCache = cache
config.requestCachePolicy = .returnCacheDataElseLoad
图片优化的关键是“先降成本,再复用”。减少解码和重复加载,滚动体验会明显提升。