TTP 缓存是优化 iOS App 性能最有效的手段之一。它能减少流量消耗、节省电池电量,并显著提升用户感知的加载速度。
HTTP 缓存主要分为两大类:强缓存和协商缓存。
1. HTTP 缓存分类
A. 强缓存 (Strong Caching)
浏览器(或 iOS 系统)直接从本地获取数据,不向服务器发送请求。
- Expires: 绝对时间(如:
Expires: Wed, 21 Oct 2026 07:28:00 GMT)。受限于客户端时钟。 - Cache-Control: 相对时间(如:
max-age=3600,表示 1 小时内有效)。它是现代标准的优先选择。
B. 协商缓存 (Conditional Caching)
本地缓存已过期,App 向服务器询问:“我这份数据还能用吗?”
- Last-Modified / If-Modified-Since: 基于文件的最后修改时间。
- ETag / If-None-Match: 基于内容的唯一哈希值(指纹)。优先级高于 Last-Modified。
- 结果:如果没变,服务器返回 304 Not Modified(不含 Body),App 继续用旧数据;如果变了,返回 200 OK 和新数据。
2. iOS 中的缓存控制 (NSURLCache)
在 iOS 中,URLSession 默认使用 URLCache.shared 来管理缓存。它会自动处理上述的 HTTP 头部逻辑。
A. 设置缓存容量
通常在 AppDelegate 或网络层初始化阶段设置,建议将磁盘缓存设置大一些。
Swift
let memoryCapacity = 4 * 1024 * 1024 // 4MB
let diskCapacity = 50 * 1024 * 1024 // 50MB
let cache = URLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "my_cache_path")
URLCache.shared = cache
B. 请求层面的缓存策略
在创建 URLRequest 时,你可以通过 cachePolicy 显式控制:
Swift
var request = URLRequest(url: url)
// 常用策略:
request.cachePolicy = .useProtocolCachePolicy // 1. 默认:遵从 HTTP 协议头
request.cachePolicy = .reloadIgnoringLocalCacheData // 2. 忽略缓存,强制刷服务器
request.cachePolicy = .returnCacheDataElseLoad // 3. 有缓存就用,没缓存再请求(适合离线模式)
request.cachePolicy = .returnCacheDataDontLoad // 4. 只读缓存,不发请求(强制离线)
3. 如何手动清理缓存
当用户点击 App 内的“清理缓存”按钮时,你可以调用:
Swift
// 清理所有缓存
URLCache.shared.removeAllCachedResponses()
// 清理特定请求的缓存
URLCache.shared.removeCachedResponse(for: request)
4. 关键点:为什么我的缓存没生效?
- 服务器响应头不支持:如果服务器返回的
Cache-Control是no-store或private(且未配置正确),iOS 不会缓存。 - HTTPS 限制:默认情况下,某些安全等级高的磁盘缓存可能不持久化 HTTPS 响应,除非显式允许。
- URL 变动:URL 字符串中哪怕多一个空格或一个随机参数(如
?timestamp=...),缓存就会失效。 - Header 冲突:如果你在
URLRequest中手动设置了Cache-Control: no-cache,会覆盖服务器的缓存指令。
总结
- 强缓存(
max-age)最快,因为根本不发请求。 - 协商缓存(
ETag)最稳,保证数据永远是最新的,且流量消耗极小。 - 在 iOS 中,尽量复用
URLCache.shared并根据业务需求选择合适的cachePolicy。