iOS技術(shù)文檔No.27 Foundation_NSCachedURLResponse,NSURLCache

NSURLCache

NSURLCache 為您的應(yīng)用的 URL 請求提供了內(nèi)存中以及磁盤上的綜合緩存機(jī)制。 作為基礎(chǔ)類庫 URL 加載系統(tǒng) 的一部分,任何通過 NSURLConnection 加載的請求都將被 NSURLCache 處理。
網(wǎng)絡(luò)緩存減少了需要向服務(wù)器發(fā)送請求的次數(shù),同時也提升了離線或在低速網(wǎng)絡(luò)中使用應(yīng)用的體驗。
當(dāng)一個請求完成下載來自服務(wù)器的回應(yīng),一個緩存的回應(yīng)將在本地保存。下一次同一個請求再發(fā)起時,本地保存的回應(yīng)就會馬上返回,不需要連接服務(wù)器。NSURLCache 會 自動 且 透明 地返回回應(yīng)。
為了好好利用 NSURLCache,你需要初始化并設(shè)置一個共享的 URL 緩存。在 iOS中這項工作需要在 -application:didFinishLaunchingWithOptions: 完成,而 OS X 中是在 –applicationDidFinishLaunching::

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
                                                       diskCapacity:20 * 1024 * 1024
                                                           diskPath:nil];
  [NSURLCache setSharedURLCache:URLCache];
}

緩存策略由請求(客戶端)和回應(yīng)(服務(wù)端)分別指定。理解這些策略以及它們?nèi)绾蜗嗷ビ绊懀菫槟膽?yīng)用程序找到最佳行為的關(guān)鍵。
NSURLRequestCachePolicy 緩存策略
NSURLRequest 有個 cachePolicy 屬性,它根據(jù)以下常量指定了請求的緩存行為:
NSURLRequestUseProtocolCachePolicy: 對特定的 URL 請求使用網(wǎng)絡(luò)協(xié)議中實現(xiàn)的緩存邏輯。這是默認(rèn)的策略。 NSURLRequestReloadIgnoringLocalCacheData:數(shù)據(jù)需要從原始地址加載。不使用現(xiàn)有緩存。 NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不僅忽略本地緩存,同時也忽略代理服務(wù)器或其他中間介質(zhì)目前已有的、協(xié)議允許的緩存。 NSURLRequestReturnCacheDataElseLoad:無論緩存是否過期,先使用本地緩存數(shù)據(jù)。如果緩存中沒有請求所對應(yīng)的數(shù)據(jù),那么從原始地址加載數(shù)據(jù)。 NSURLRequestReturnCacheDataDontLoad:無論緩存是否過期,先使用本地緩存數(shù)據(jù)。如果緩存中沒有請求所對應(yīng)的數(shù)據(jù),那么放棄從原始地址加載數(shù)據(jù),請求視為失敗(即:“離線”模式)。 NSURLRequestReloadRevalidatingCacheData:從原始地址確認(rèn)緩存數(shù)據(jù)的合法性后, 必須得得到服務(wù)端確認(rèn)有效才使用(貌似是NSURLRequestUseProtocolCachePolicy 中的一種情況),緩存數(shù)據(jù)就可以使用,否則從原始地址加載。
注: 1.URL Loading System默認(rèn)只支持如下5中協(xié)議: 其中只有http://和https://才有緩存策略.
(1) http://
(2) https://
(3) ftp://
(4) file://
(5) data://
2.NSURLRequestReloadIgnoringLocalAndRemoteCacheData 和 NSURLRequestReloadRevalidatingCacheData 根本沒有實現(xiàn)!
關(guān)于NSURLRequestCachePolicy,以下才是你實際需要了解的東西:

1.png

HTTP 緩存語義
因為 NSURLConnection 被設(shè)計成支持多種協(xié)議——包括 FTP、HTTP、HTTPS——所以 URL 加載系統(tǒng)用一種協(xié)議無關(guān)的方式指定緩存。為了本文的目的,緩存用術(shù)語 HTTP 語義來解釋。
HTTP 請求和回應(yīng)用 headers 來交換元數(shù)據(jù),如字符編碼、MIME 類型和緩存指令等。
Request Cache Headers
在默認(rèn)情況下,NSURLRequest 會用當(dāng)前時間決定是否返回緩存的數(shù)據(jù)。為了更精確地控制,允許使用以下請求頭:
If-Modified-Since - 這個請求頭與 Last-Modified 回應(yīng)頭相對應(yīng)。把這個值設(shè)為同一終端最后一次請求時返回的 Last-Modified 字段的值。 If-None-Match - 這個請求頭與與 Etag 回應(yīng)頭相對應(yīng)。使用同一終端最后一次請求的 Etag 值。
Response Cache Headers
NSHTTPURLResponse 包含多個 HTTP 頭,當(dāng)然也包括以下指令來說明回應(yīng)應(yīng)當(dāng)如何緩存:
Cache-Control - 這個頭必須由服務(wù)器端指定以開啟客戶端的 HTTP 緩存功能。這個頭的值可能包含 max-age(緩存多久),是公共 public 還是私有 private,或者不緩存 no-cache 等信息。詳情請參閱 Cache-Control section of RFC 2616。 除了 Cache-Control 以外,服務(wù)器也可能發(fā)送一些附加的頭用于根據(jù)需要有條件地請求:
Last-Modified - 這個頭的值表明所請求的資源上次修改的時間。例如,一個客戶端請求最近照片的時間線,/photos/timeline,Last-Modified 的值可以是最近一張照片的拍攝時間。 Etag - 這是 “entity tag” 的縮寫,它是一個表示所請求資源的內(nèi)容的標(biāo)識符。在實踐中,Etag 的值可以是類似于資源的 MD5 之類的東西。這對于那些動態(tài)生成的、可能沒有明顯的 Last-Modified 值的資源非常有用。
NSURLConnectionDelegate
一旦收到了服務(wù)器的回應(yīng),NSURLConnection 的代理就有機(jī)會在 -connection:willCacheResponse: 中指定緩存數(shù)據(jù)。
NSCachedURLResponse 是個包含 NSURLResponse 以及它對應(yīng)的緩存中的 NSData 的類。
在 -connection:willCacheResponse: 中,cachedResponse 對象會根據(jù) URL 連接返回的結(jié)果自動創(chuàng)建。因為 NSCachedURLResponse 沒有可變部分,為了改變 cachedResponse 中的值必須構(gòu)造一個新的對象,把改變過的值傳入 –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)將不會緩存。

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
    return nil;
}

如果不實現(xiàn)此方法,NSURLConnection 就簡單地使用本來要傳入 -connection:willCacheResponse: 的那個緩存對象,所以除非你需要改變一些值或者阻止緩存,否則這個代理方法不必實現(xiàn)。
NSURLCache & NSCachedURLResponse常用方法
NSURLCache
1.初始化相關(guān)的幾個方法:sharedURLCache;setSharedURLCache;initWithMemoryCapacity sharedURLCache方法返回一個NSURLCache實例。 默認(rèn)情況下,內(nèi)存是4M,4* 1024 * 1024;Disk為20M,20 * 1024 * 1024;路徑在(NSHomeDirectory)/Library/Caches/(current application name, [[NSProcessInfo processInfo] processName]) setSharedURLCache可以通過這個方法來改變默認(rèn)的NSURLCache。通過initWithMemoryCapacity來定制自己的NSURLCache。
2.cache使用相關(guān)的幾個方法:

cachedResponseForRequest;storeCachedResponse;removeCachedResponseForRequest;
removeAllCachedResponses 
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request; 
如果對應(yīng)的NSURLRequest沒有cached的response那么返回nil 
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest*)request; 
為特定的NSURLRequest做cache
 - (void)removeCachedResponseForRequest:(NSURLRequest *)request; 
移除特定NSURLRequest的cache 
- (void)removeAllCachedResponses;
 移除所有的cache

3.property方法

- (NSUInteger)memoryCapacity; 
- (NSUInteger)diskCapacity;
 - (void)setMemoryCapacity:(NSUInteger)memoryCapacity; 
可能會導(dǎo)致內(nèi)存中的內(nèi)存被截斷
 - (void)setDiskCapacity:(NSUInteger)diskCapacity; 
- (NSUInteger)currentMemoryUsage; 
- (NSUInteger)currentDiskUsage;

4.Misc
a. NSURLCache在每個UIWebView的的NSURLRequest請求中都會被調(diào)用。
b. ios設(shè)備上NSURLCache默認(rèn)只能進(jìn)行內(nèi)存緩存??梢酝ㄟ^子類化NSURLCache來實現(xiàn)自定義的版本從而實現(xiàn)在DISK上緩存內(nèi)容。
c. 需要重寫cachedResponseForRequest,這個會在請求發(fā)送前會被調(diào)用,從中我們可以判定是否針對此NSURLRequest返回本地數(shù)據(jù)。
d. 如果本地沒有緩存就調(diào)用下面這條語句:return [super cachedResponseForRequest:request];
NSCachedURLResponse
包裝了一下系統(tǒng)緩存機(jī)制的對象,保持了緩存對象的個性和特性。
1.NSURLCacheStoragePolicy 緩存策略有三種
enum
{
NSURLCacheStorageAllowed,
NSURLCacheStorageAllowedInMemoryOnly,
NSURLCacheStorageNotAllowed,
};
默認(rèn)是第一種。不過在iOS的上官方文檔上有這么一個解釋: Important: iOS ignores this cache policy, and instead treats it asNSURLCacheStorageAllowedInMemoryOnly. 也就是說iOS上只有內(nèi)存緩存,沒有磁盤緩存。
2.構(gòu)造方法

- (id)initWithResponse:(NSURLResponse *)response data:(NSData *)data; 
- (id)initWithResponse:(NSURLResponse *)response data:(NSData *)data userInfo:(NSDictionary *)userInfo storagePolicy:(NSURLCacheStoragePolicy)storagePolicy;
3.Open API 
- (NSURLResponse *)response; 
- (NSData *)data; 
- (NSDictionary *)userInfo; - (NSURLCacheStoragePolicy)storagePolicy;

注意事項
正如它那個毫無關(guān)系但是名字相近的小伙伴 NSCache 一樣,NSURLCache 也是有一些特別的。
Peter Steinberger 關(guān)于這個主題寫了一篇優(yōu)秀的文章,在深入研究內(nèi)部細(xì)節(jié)后實現(xiàn)他自己的 NSURLCache 子類。NSURLCache 提醒著我們熟悉我們正在操作的系統(tǒng)是多么地重要。
Daniel Pasco 在 Black Pixel 上的另一篇文章 描述了一些與服務(wù)器通信時不設(shè)置緩存頭的意外的默認(rèn)行為。
無數(shù)開發(fā)者嘗試自己做一個簡陋而脆弱的系統(tǒng)來實現(xiàn)網(wǎng)絡(luò)緩存的功能,殊不知 NSURLCache 只要兩行代碼就能搞定且好上100倍。甚至更多開發(fā)者根本不知道網(wǎng)絡(luò)緩存的好處,也從未嘗試過,導(dǎo)致他們的應(yīng)用向服務(wù)器作了無數(shù)不必要的網(wǎng)絡(luò)請求。
所以如果你想看到世界的變化,你想確保你有程序總以正確的方式開啟,在 -application:didFinishLaunchingWithOptions: 設(shè)置一個共享的 NSURLCache 吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容