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