在iOS app的開發過程當中,網絡數據的緩存一直來講都是一件常見,但又繁瑣的任務,常常會有各類老大們提出這樣那樣的緩存要求。
通常而言緩存技術都無外乎如下幾點。第一種則是使用系統內置的緩存處理機制,就如本文所提到的,包括了使用一些第三方庫,也是使用系統底層內置的緩存。另一種則是使用額外的緩存工具,好比數據庫、文件存儲等進行保存,同時本身來控制緩存的策略。
緩存的方式不少,不管你選擇使用哪種,我相信理解這些系統底層的處理機制對你最終選擇本身的處理策略會頗有幫助。數據庫
NSURLCache是iOS系統用於實現網絡緩存的一個組件,被放於NSURL Loading這一個功能組件中。
在NSURLConnection加載系統中,緩存被設計爲request對象的一個屬性,由NSURLRequest對象的cachePolicy屬性指定。而在NSURLSession加載系統中,緩存被設計爲NSURLSessionConfiguration對像的一個屬性,該屬性所指定的策略被該session的全部request所共享。緩存
NSURLRequestUseProtocolCachePolicy是默認的緩存策略,它使用當前URL的協議中預置的緩存策略,不管這個協議是http,仍是說你本身定義協議。
對於咱們常見的http協議來講,這個策略根據請求的頭來執行緩存策略。服務器能夠在返回的響應頭中加入Expires策略或者Cache-Control策略來告訴客戶端應該執行的緩存行爲,同時配合#Last-Modified#等頭來控制刷新的時機。
有關具體的http緩存策略這裏不詳述。服務器
NSURLRequestReloadIgnoringCacheData 這個策略則根本不會緩存數據網絡
NSURLRequestReturnCacheDataElseLoad 這個策略比較有趣,它會一直償試讀取緩存數據,直到沒法沒有緩存數據的時候,纔會去請求網絡。這個策略有一個重大的缺陷致使它根本沒法被使用,即它根本沒有對緩存的刷新時機進行控制,若是你要去使用它,那麼須要額外的進行對緩存過時進行控制。session
這個選項只讀緩存,不管什麼時候都不會進行網絡請求。app
在默認的這幾個選項之下,若是你須要對緩存進行精確的控制或者修改,則須要實現NSURLProtocol子類了工具
NSURLSession的數據和上傳任務,能夠實現URLSession:dataTask:willCacheResponse:completionHandler:
方法。另外,下載的任務在這裏是不可用的。設計
對於NSURLConnection,則實現connection:willCacheResponse:
方法代理
NSURLSession提供一個block來告之會話須要緩存什麼東西,而NSURLConnection代理則須要返回一個NSURLCachedResponse對象。
通常來講,若是你須要修改須要緩存的內容,那麼你須要新建立一個NSURLCachedResponse對象來被緩存,同時用於下一次的返回。另外返回nil則會阻止緩存行爲。如:code
\- (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; }
在第一次請求到服務器資源的時候,服務器須要使用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 則由客戶端發送,標識客戶端所記錄的,資源的最後修改時間。服務器接收到帶有該請求頭的請求時,會使用該時間與資源的最後修改時間進行對比,若是發現資源未被修改過,則直接返回HTTP 304而不返回包體,告訴客戶端直接使用本地的緩存。不然響應完整的消息內容。
Etag 由服務器發送,告之當資源在服務器上的一個惟一標識符。客戶端請求時,若是發現資源過時(使用Cache-Control的max-age),發現資源具備Etag聲明,這時請求服務器時則帶上If-None-Match頭,服務器收到後則與資源的標識進行對比,決定返回200或者304。