题目
设计一个高性能的图片缓存组件
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
内存管理,磁盘存储,多线程处理,缓存策略,性能优化
快速回答
设计高性能图片缓存需实现:
- 三级缓存架构:内存缓存(NSCache)+ 磁盘缓存(文件系统)+ 网络下载
- 线程安全:使用串行队列管理读写操作
- 缓存淘汰策略:LRU内存管理 + 文件过期清理
- 解码优化:后台线程解码图片并缩放至视图尺寸
- 请求合并:对相同URL的并发请求进行合并
核心架构设计
高性能图片缓存应包含三级结构:
class ImageCache {
// 1. 内存缓存(线程安全访问)
private let memoryCache = NSCache<NSString, UIImage>()
// 2. 磁盘缓存目录
private let diskCacheURL: URL
// 3. 操作队列与状态管理
private let serialQueue = DispatchQueue(label: "com.imageCache.queue")
private var runningRequests = [String: [ImageRequest]]()
}关键技术实现
1. 内存缓存优化
- 使用
NSCache自动释放内存(优于Dictionary) - 设置成本计算:
memoryCache.totalCostLimit = 1024 * 1024 * 100 // 100MB - 成本计算规则:
cost = image.size.height * image.size.width * 4(RGBA)
2. 磁盘缓存实现
// 文件存储路径
func storeToDisk(data: Data, key: String) {
let fileURL = diskCacheURL.appendingPathComponent(key)
try? data.write(to: fileURL)
}
// 使用FileManager属性记录访问时间
let attributes: [FileAttributeKey: Any] = [
.creationDate: Date(),
.modificationDate: Date() // 用于LRU
]3. 多线程处理
- 下载队列:
OperationQueue限制最大并发数 - 解码队列:专用后台队列处理CPU密集型解码
- 回调主线程:
DispatchQueue.main.async更新UI
4. 请求合并机制
func loadImage(url: URL, completion: @escaping (UIImage?) -> Void) {
serialQueue.async {
// 存在相同请求时追加回调
if var existingRequests = self.runningRequests[url.absoluteString] {
existingRequests.append(ImageRequest(completion: completion))
return
}
// 创建新请求
let request = ImageRequest(completion: completion)
self.runningRequests[url.absoluteString] = [request]
self.startDownload(url: url) // 触发下载
}
}缓存策略实现
LRU内存淘汰
// 使用双向链表实现
class LRUCacheNode {
let key: NSString
var value: UIImage
var prev: LRUCacheNode?
var next: LRUCacheNode?
}
// 访问时移动节点到链表头部
func moveToHead(_ node: LRUCacheNode) {
removeNode(node)
addToHead(node)
}磁盘清理策略
- 后台定期清理(如App进入后台时)
- 按文件修改时间排序,删除最旧文件
- 设置最大磁盘空间(如200MB)
性能优化点
- 解码优化:使用
UIGraphicsImageRenderer替代UIGraphicsBeginImageContext - 降采样:对大图使用
ImageIO进行缩略图解码 - 预加载:对即将显示的图片触发低优先级下载
常见错误
- 线程爆炸:未限制下载队列并发数导致卡顿
- 内存峰值:同步解码大尺寸图片阻塞主线程
- 缓存穿透:未处理重复请求导致多次下载
- 磁盘碎片:频繁小文件写入降低IO性能
扩展知识
- 渐进式加载:支持JPEG渐进式渲染
- 格式优化:根据设备选择HEIC/JPEG格式存储
- 响应式设计:监听
UIApplication.didReceiveMemoryWarningNotification清空内存缓存 - 性能指标:使用Instruments的Core Animation和Time Profiler调试