為什麼要理解NSURLCache?
在iOS app的開發過程中,網路資料的快取一直來說都是一件常見,但又繁瑣的任務,經常會有各種老大們提出這樣那樣的快取要求。
一般而言快取技術都無外乎以下幾點。第一種則是使用系統內建的快取處理機制,就如本文所提到的,包括了使用一些第三方庫,也是使用系統底層內建的快取。另外一種則是使用額外的快取工具,比如資料庫、檔案儲存等進行儲存,同時自己來控制快取的策略。
快取的方式很多,無論你選擇使用哪一種,我相信理解這些系統底層的處理機制對你最終選擇自己的處理策略會很有幫助。
NSURLCache
NSURLCache是iOS系統用於實現網路快取的一個元件,被放於NSURL Loading這一個功能元件中。
在NSURLConnection載入系統中,快取被設計為request物件的一個屬性,由NSURLRequest物件的cachePolicy屬性指定。而在NSURLSession載入系統中,快取被設計為NSURLSessionConfiguration對像的一個屬性,該屬性所指定的策略被該session的所有request所共享。
可選的快取策略
NSURLRequestUseProtocolCachePolicy
NSURLRequestUseProtocolCachePolicy是預設的快取策略,它使用當前URL的協議中預置的快取策略,無論這個協議是http,還是說你自己定義協議。
對於我們常見的http協議來說,這個策略根據請求的頭來執行快取策略。伺服器可以在返回的響應頭中加入Expires策略或者Cache-Control策略來告訴客戶端應該執行的快取行為,同時配合#Last-Modified#等頭來控制重新整理的時機。
有關具體的http快取策略這裡不詳述。
NSURLRequestReloadIgnoringCacheData
NSURLRequestReloadIgnoringCacheData 這個策略則根本不會快取資料
NSURLRequestReturnCacheDataElseLoad
NSURLRequestReturnCacheDataElseLoad 這個策略比較有趣,它會一直償試讀取快取資料,直到無法沒有快取資料的時候,才會去請求網路。這個策略有一個重大的缺陷導致它根本無法被使用,即它根本沒有對快取的重新整理時機進行控制,如果你要去使用它,那麼需要額外的進行對快取過期進行控制。
NSURLRequestReturnCacheDataDontLoad
這個選項只讀快取,無論何時都不會進行網路請求。
精確的快取控制
在預設的這幾個選項之下,如果你需要對快取進行精確的控制或者修改,則需要實現NSURLProtocol子類了
-
NSURLSession的資料和上傳任務,可以實現
URLSession:dataTask:willCacheResponse:completionHandler:
方法。另外,下載的任務在這裡是不可用的。 -
對於NSURLConnection,則實現
connection:willCacheResponse:
方法
NSURLSession提供一個block來告之會話需要快取什麼東西,而NSURLConnection代理則需要返回一個NSURLCachedResponse物件。
一般來說,如果你需要修改需要快取的內容,那麼你需要新建立一個NSURLCachedResponse物件來被快取,同時用於下一次的返回。另外返回nil則會阻止快取行為。如:
- (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];
}
或者
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
與HTTP伺服器進行互動的簡單說明
Cache-Control頭
在第一次請求到伺服器資源的時候,伺服器需要使用Cache-Control這個響應頭來指定快取策略,它的格式如下:Cache-Control:max-age=xxxx
,這個頭指指明快取過期的時間
Cache-Control頭具有如下選項:
-
public: 指示可被任何區快取
-
private
-
no-cache: 指定該響應訊息不能被快取
-
no-store: 指定不應該快取
-
max-age: 指定過期時間
-
min-fresh:
-
max-stable:
Last-Modified/If-Modified-Since
Last-Modified 是由伺服器返回響應頭,標識資源的最後修改時間.
If-Modified-Since 則由客戶端傳送,標識客戶端所記錄的,資源的最後修改時間。伺服器接收到帶有該請求頭的請求時,會使用該時間與資源的最後修改時間進行對比,如果發現資源未被修改過,則直接返回HTTP 304而不返回包體,告訴客戶端直接使用本地的快取。否則響應完整的訊息內容。
Etag/If-None-Match
Etag 由伺服器傳送,告之當資源在伺服器上的一個唯一識別符號。
客戶端請求時,如果發現資源過期(使用Cache-Control的max-age),發現資源具有Etag宣告,這時請求伺服器時則帶上If-None-Match頭,伺服器收到後則與資源的標識進行對比,決定返回200或者304。