一、簡介
- NSURLCache 為應用的 URL 請求提供了內存以及磁盤上的綜合緩存機制,作為基礎類庫 URL 加載的一部分,任何通過 NSURLConnection 加載的請求都將被 NSURLCache 處理。
- 網絡緩存減少了需要向服務器發送請求的次數,同時也提升了離線或在低速網絡中使用應用的體驗。
- 當一個請求完成下載來自服務器的回應,一個緩存的回應將在本地保存。下一次同一個請求再發起時,本地保存的回應就會馬上返回,不需要連接服務器。NSURLCache
會 自動 且 透明 地返回回應。 - 為了好好利用 NSURLCache
,你需要初始化并設置一個共享的 URL 緩存。在 iOS 中這項工作需要在 -application:didFinishLaunchingWithOptions:
完成
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];}
緩存策略由請求(客戶端)和回應(服務端)分別指定。理解這些策略以及它們如何相互影響,是為您的應用程序找到最佳行為的關鍵。
二、NSURLRequestCachePolicy
- NSURLRequest 有個 cachePolicy 屬性,它根據以下常量指定了請求的緩存行為:
- NSURLRequestUseProtocolCachePolicy: 對特定的 URL 請求使用網絡協議中實現的緩存邏輯。這是默認的策略。
- NSURLRequestReloadIgnoringLocalCacheData:數據需要從原始地址加載。不使用現有緩存。
- NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不僅忽略本地緩存,同時也忽略代理服務器或其他中間介質目前已有的、協議允許的緩存。
- NSURLRequestReturnCacheDataElseLoad:無論緩存是否過期,先使用本地緩存數據。如果緩存中沒有請求所對應的數據,那么從原始地址加載數據。
- NSURLRequestReturnCacheDataDontLoad:無論緩存是否過期,先使用本地緩存數據。如果緩存中沒有請求所對應的數據,那么放棄從原始地址加載數據,請求視為失敗(即:“離線”模式)。
- NSURLRequestReloadRevalidatingCacheData:從原始地址確認緩存數據的合法性后,緩存數據就可以使用,否則從原始地址加載。
注意:
NSURLRequestReloadIgnoringLocalAndRemoteCacheData
和NSURLRequestReloadRevalidatingCacheData
根本沒有實現(Link to Radar)更加加深了混亂程度!
- 關于 NSURLRequestCachePolicy
,以下才是你 實際 需要了解的東西:
常量 -------------------------------意義
UseProtocolCachePolicy------------- --默認行為
ReloadIgnoringLocalCacheData---------不使用緩存
ReturnCacheDataElseLoad-------------使用緩存(不管它是否過期),如果緩存中沒有,那從網絡加載吧
ReturnCacheDataDontLoad------------離線模式:使用緩存(不管它是否過期),但是不從網絡加載
NSURLRequestReloadIgnoringLocalAndRemoteCacheData,NSURLRequestReloadRevalidatingCacheData根本沒有實現
三、HTTP 緩存語義
- 因為 NSURLConnection被設計成支持多種協議——包括 FTP、HTTP、HTTPS——所以 URL 加載系統用一種協議無關的方式指定緩存。為了本文的目的,緩存用術語 HTTP 語義來解釋
- HTTP 請求和回應用 headers 來交換元數據,如字符編碼、MIME 類型和緩存指令等。
- Request Cache Headers
- 在默認情況下,NSURLRequest 會用當前時間決定是否返回緩存的數據。為了更精確地控制,允許使用以下請求頭:
- If-Modified-Since- 這個請求頭與 Last-Modified 回應頭相對應。把這個值設為同一終端最后一次請求時返回的 Last-Modified 字段的值。
- If-None-Match - 這個請求頭與與 Etag 回應頭相對應。使用同一終端最后一次請求的 Etag 值。
- 在默認情況下,NSURLRequest 會用當前時間決定是否返回緩存的數據。為了更精確地控制,允許使用以下請求頭:
- Response Cache Headers
- NSHTTPURLResponse 包含多個 HTTP 頭,當然也包括以下指令來說明回應應當如何緩存:
- Cache-Control - 這個頭 必須由服務器端 指定以開啟客戶端的 HTTP 緩存功能。這個頭的值可能包含 max-age(緩存多久),是公共 public 還是私有 private,或者不緩存no-cache 等信息。詳情請參閱 Cache-Control section of RFC 2616。
- 除了 Cache-Control 以外,服務器也可能發送一些附加的頭用于根據需要有條件地請求(如上一節所提到的)
- Last-Modified - 這個頭的值表明所請求的資源上次修改的時間。例如,一個客戶端請求最近照片的時間線,/photos/timeline,Last-Modified 的值可以是最近一張照片的拍攝時間。
- Etag - 這是 “entity tag” 的縮寫,它是一個表示所請求資源的內容的標識符。在實踐中,Etag 的值可以是類似于資源的 MD5 之類的東西。這對于那些動態生成的、可能沒有明顯的 Last-Modified
值的資源非常有用。
- NSHTTPURLResponse 包含多個 HTTP 頭,當然也包括以下指令來說明回應應當如何緩存:
- NSURLConnectionDelegate
- 一旦收到了服務器的回應,NSURLConnection 的代理就有機會在 -connection:willCacheResponse: 中指定緩存數據。
- NSCachedURLResponse 是個包含 NSURLResponse 以及它對應的緩存中的 NSData 的類.
- 在 -connection:willCacheResponse: 中,cachedResponse 對象會根據 URL 連接返回的結果自動創建。因為 NSCachedURLResponse 沒有可變部分,為了改變 cachedResponse 中的值必須構造一個新的對象,把改變過的值傳入 –initWithResponse:data:userInfo:storagePolicy:,例如:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{ NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy];
NSMutableData *mutableData = [[cachedResponse data] mutableCopy];
NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly;
// ...
return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
data:mutableData
userInfo:mutableUserInfo
storagePolicy:storagePolicy];
}
如果 -connection:willCacheResponse: 返回 nil,回應將不會緩存。
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}