NSURLCache
爲您的應用的 URL 請求提供了內存中以及磁盤上的綜合緩存機制。 做爲基礎類庫 URL 加載系統 的一部分,任何經過 NSURLConnection
加載的請求都將被 NSURLCache
處理。html
網絡緩存減小了須要向服務器發送請求的次數,同時也提高了離線或在低速網絡中使用應用的體驗。ios
當一個請求完成下載來自服務器的迴應,一個緩存的迴應將在本地保存。下一次同一個請求再發起時,本地保存的迴應就會立刻返回,不須要鏈接服務器。NSURLCache
會 自動 且 透明 地返回迴應。git
爲了好好利用 NSURLCache
,你須要初始化並設置一個共享的 URL 緩存。在 iOS 中這項工做須要在 -application:didFinishLaunchingWithOptions:
完成,而 OS X 中是在 –applicationDidFinishLaunching:
:github
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil]; [NSURLCache setSharedURLCache:URLCache]; }
緩存策略由請求(客戶端)和迴應(服務端)分別指定。理解這些策略以及它們如何相互影響,是爲您的應用程序找到最佳行爲的關鍵。objective-c
NSURLRequestCachePolicy
NSURLRequest
有個 cachePolicy
屬性,它根據如下常量指定了請求的緩存行爲:緩存
NSURLRequestUseProtocolCachePolicy
: 對特定的 URL 請求使用網絡協議中實現的緩存邏輯。這是默認的策略。NSURLRequestReloadIgnoringLocalCacheData
:數據須要從原始地址加載。不使用現有緩存。NSURLRequestReloadIgnoringLocalAndRemoteCacheData
:不只忽略本地緩存,同時也忽略代理服務器或其餘中間介質目前已有的、協議容許的緩存。NSURLRequestReturnCacheDataElseLoad
:不管緩存是否過時,先使用本地緩存數據。若是緩存中沒有請求所對應的數據,那麼從原始地址加載數據。NSURLRequestReturnCacheDataDontLoad
:不管緩存是否過時,先使用本地緩存數據。若是緩存中沒有請求所對應的數據,那麼放棄從原始地址加載數據,請求視爲失敗(即:「離線」模式)。NSURLRequestReloadRevalidatingCacheData
:從原始地址確認緩存數據的合法性後,緩存數據就可使用,不然從原始地址加載。你並不會驚奇於這些值不被透徹理解且常常搞混淆。服務器
NSURLRequestReloadIgnoringLocalAndRemoteCacheData
和NSURLRequestReloadRevalidatingCacheData
根本沒有實現(Link to Radar)更加加深了混亂程度!網絡
關於NSURLRequestCachePolicy
,如下才是你 實際 須要瞭解的東西:app
常量 | 意義 |
---|---|
UseProtocolCachePolicy | 默認行爲 |
ReloadIgnoringLocalCacheData | 不使用緩存 |
ReturnCacheDataElseLoad | 使用緩存(無論它是否過時),若是緩存中沒有,那從網絡加載吧 |
ReturnCacheDataDontLoad | 離線模式:使用緩存(無論它是否過時),可是不從網絡加載 |
由於 NSURLConnection
被設計成支持多種協議——包括 FTP
、HTTP
、HTTPS
——因此 URL 加載系統用一種協議無關的方式指定緩存。爲了本文的目的,緩存用術語 HTTP 語義來解釋。ui
HTTP 請求和迴應用 headers 來交換元數據,如字符編碼、MIME 類型和緩存指令等。
在默認狀況下,NSURLRequest
會用當前時間決定是否返回緩存的數據。爲了更精確地控制,容許使用如下請求頭:
If-Modified-Since
- 這個請求頭與 Last-Modified
迴應頭相對應。把這個值設爲同一終端最後一次請求時返回的 Last-Modified
字段的值。If-None-Match
- 這個請求頭與與 Etag
迴應頭相對應。使用同一終端最後一次請求的Etag
值。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
值的資源很是有用。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; }
若是不實現此方法,NSURLConnection
就簡單地使用原本要傳入 -connection:willCacheResponse:
的那個緩存對象,因此除非你須要改變一些值或者阻止緩存,不然這個代理方法沒必要實現。
正如它那個毫無關係可是名字相近的小夥伴 NSCache
同樣,NSURLCache
也是有一些特別的。
在 iOS 5,磁盤緩存開始支持,但僅支持 HTTP,非 HTTPS(iOS 6 中增長了此支持)。Peter Steinberger 關於這個主題寫了一篇優秀的文章,在深刻研究內部細節後實現他本身的 NSURLCache 子類。
Daniel Pasco 在 Black Pixel 上的另外一篇文章 描述了一些與服務器通訊時不設置緩存頭的意外的默認行爲。
NSURLCache
提醒着咱們熟悉咱們正在操做的系統是多麼地重要。開發 iOS 或 OS X 程序時,這些系統中的重中之重,非 URL Loading System莫屬。
無數開發者嘗試本身作一個簡陋而脆弱的系統來實現網絡緩存的功能,卻不知 NSURLCache
只要兩行代碼就能搞定且好上100倍。甚至更多開發者根本不知道網絡緩存的好處,也從何嘗試過,致使他們的應用向服務器做了無數沒必要要的網絡請求。
因此若是你想看到世界的變化,你想確保你有程序總以正確的方式開啓,在 -application:didFinishLaunchingWithOptions:
設置一個共享的 NSURLCache
吧。