跳到主要内容

设计图片缓存框架

问题

如何设计一个高性能的 iOS 图片缓存框架?

答案

三级缓存架构

核心组件设计

// 内存缓存 - NSCache
class MemoryCache {
private let cache = NSCache<NSString, UIImage>()

init(countLimit: Int = 100, totalCostLimit: Int = 50 * 1024 * 1024) {
cache.countLimit = countLimit
cache.totalCostLimit = totalCostLimit // 50MB
}

func get(_ key: String) -> UIImage? {
cache.object(forKey: key as NSString)
}

func set(_ image: UIImage, forKey key: String) {
let cost = Int(image.size.width * image.size.height * image.scale * 4)
cache.setObject(image, forKey: key as NSString, cost: cost)
}
}

// 磁盘缓存
class DiskCache {
private let directory: URL
private let maxAge: TimeInterval = 7 * 24 * 3600 // 7 天
private let queue = DispatchQueue(label: "com.app.diskCache")

func get(_ key: String) -> Data? {
let path = filePath(for: key)
return try? Data(contentsOf: path)
}

func set(_ data: Data, forKey key: String) {
queue.async {
try? data.write(to: self.filePath(for: key))
}
}

private func filePath(for key: String) -> URL {
let hash = SHA256.hash(data: Data(key.utf8))
let filename = hash.map { String(format: "%02x", $0) }.joined()
return directory.appendingPathComponent(filename)
}
}

关键设计点

设计点方案
缓存 KeyURL 的 SHA256 哈希
内存淘汰NSCache 自动 LRU
磁盘淘汰定期清理过期文件 + 总大小限制
图片解码后台线程强制解码,避免主线程卡顿
下载去重URL 作为 key,相同 URL 合并下载回调
取消机制返回 token,cell 复用时取消前一个请求

常见面试问题

Q1: 为什么用 NSCache 而不是 Dictionary?

答案:NSCache 自动在内存紧张时释放对象、线程安全、支持 cost 和 count 限制。Dictionary 需要自己实现所有这些功能。

相关链接