標籤:
我讀過一些開源項目的網路請求緩衝的代碼,基本上都是採用在本地存檔案的方式進行緩衝。如果你打算在你的項目中加入網路請求的緩衝,可能你並不需要自己造一個輪子,了解一下 NSURLCache 就足夠。本文為大家接收的就是ios開發中的NSURLCache相關使用,一起來看看吧。
緩衝
首先, NSURLCache 提供的是記憶體以及磁碟的綜合緩衝機制。許多文章談到,使用NSURLCache 之前需要在 AppDelegate 中緩衝空間的設定:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURLCache *URLCache = [[NSURLCachealloc] initWithMemoryCapacity:4 * 1024 * 1024
diskCapacity:20 * 1024 * 1024
diskPath:nil];
[NSURLCachesetSharedURLCache:URLCache];
}
然而如果你不添加上面的代碼,並且運行如下代碼,可以看到:
print(NSURLCache.sharedURLCache().diskCapacity)//output://10000000
print(NSURLCache.sharedURLCache().memoryCapacity)//output://512000
也就是說,其實預設就已經設定好了512kb的記憶體緩衝空間,以及10MB的磁碟緩衝空間。可能你的代碼中並沒有寫任何與 NSURLCache 有關的東西,但其實它已經默默的開始幫你進行緩衝了。
已經緩衝上了,但是怎麼使用緩衝呢?請繼續往下。
緩衝策略
GET
不用多說, NSURLCache 只會對你的 GET 請求進行緩衝。
NSURLRequestCachePolicy
NSURLRequest 中有個屬性:
public var cachePolicy: NSURLRequestCachePolicy { get }
你可以通過這個屬性來佈建要求的緩衝策略,
public enum NSURLRequestCachePolicy : UInt {
case UseProtocolCachePolicy // 預設值
case ReloadIgnoringLocalCacheData // 不使用快取資料
case ReloadIgnoringLocalAndRemoteCacheData // Unimplemented
public static var ReloadIgnoringCacheData: NSURLRequestCachePolicy { get }
case ReturnCacheDataElseLoad // 無論緩衝是否到期都是用緩衝,沒有緩衝就進行網路請求
case ReturnCacheDataDontLoad // 無論緩衝是否到期都是用緩衝,沒有緩衝也不會進行網路請求
case ReloadRevalidatingCacheData // Unimplemented
}
其實其他幾個值都比較好理解,唯獨預設值 UseProtocolCachePolicy 讓我不太懂。
字面上的意思是 按照協議的緩衝策略進行緩衝 ,那麼這是什麼協議呢? http協議。
詳細:RFC 2616, Section 13
伺服器返回的回應標頭中會有這樣的欄位: Cache-Control: max-age or Cache-Control: s- maxage ,通過 Cache-Control 來指定緩衝策略, max-age 來表示到期時間。根據這些欄位緩衝機制再採用如下策略:
· 如果本地沒有快取資料,則進行網路請求。
· 如果本地有緩衝,並且緩衝沒有失效,則使用緩衝。
· 如果緩衝已經失效,則詢問伺服器資料是否改變,如果沒改變,依然使用緩衝,如果改變了則請求新資料。
· 如果沒有指定是否失效,那麼系統將自己判斷緩衝是否失效。(通常認為是6-24小時的有效時間)
其實我以前對 Cache-Control 之類的也並不太瞭解 T_T,自己默默的print了一下回應標頭,你可以看到:
print((responseas? NSHTTPURLResponse)?.allHeaderFields)
//回應標頭中:Cache-Control: no-cache
這也就是為什麼,雖然 NSURLCache 一直在默默的緩衝,但是我並沒有感受到,當然或許你那裡不一樣。這個 no-cache 就表示不緩衝。
這裡要額外提一句,看到網上有同學說自己出現了某個請求資料一直使用緩衝,沒有被更新。這種情況可能就是伺服器返回的 Cache-Control 有誤。
開啟沙箱路徑下的Library/Caches 中,你可以看到快取檔案:
這可以說明存在磁碟上的資料是存在資料庫裡的,效能不用擔心。開啟資料庫檔案就可以看到請求的資料。
在 cfurl_cache_response 表中可以看到有一個欄位是 request_key ,通過裡面的值可以推斷每一個 response 是通過請求的 url+參數 來作為 key 儲存的。
當然,經過我的多次實驗,在 Cache-Control: no-cache 的情況下, NSURLCache也會進行緩衝,但是並不使用快取資料。
總結一下:預設情況下 NSURLCache 的緩衝策略是根據http協議來的,伺服器通過 Cache-Control: max-age 欄位來告訴 NSURLCache 是否需要快取資料。
緩衝封裝
如果你不打算採用http協議的緩衝策略,依然可以使用 NSURLCache 進行緩衝。
public funccachedResponseForRequest(request: NSURLRequest) -> NSCachedURLResponse?
你可以通過這個方法,傳入請求,來擷取緩衝。 NSCachedURLResponse 儲存了上次請求的資料以及回應標頭。
public funcstoreCachedResponse(cachedResponse: NSCachedURLResponse, forRequestrequest: NSURLRequest)
NSURLSessionDelegate 協議中有如下方法,可以對即將緩衝的資料進行修改,添加userInfo,在代理方法中必須調用completionHandler,傳入將要緩衝的資料,如果傳nil則表示不緩衝。
optionalpublic funcURLSession(session: NSURLSession,
dataTask: NSURLSessionDataTask,
willCacheResponseproposedResponse: NSCachedURLResponse,
completionHandler: (NSCachedURLResponse?) -> Void)
在 Alamofire 中可以這樣寫:
Alamofire.Manager
.sharedInstance
.delegate
.dataTaskWillCacheResponse = { (session, task, cachedResponse) -> NSCachedURLResponse? in
var userInfo = [NSObject : AnyObject]()
// 設定userInfo
return NSCachedURLResponse(response: cachedResponse.response,
data: cachedResponse.data,
userInfo: userInfo,
storagePolicy: cachedResponse.storagePolicy)
}
來源:伯樂線上
iOS 網路請求緩衝:NSURLCache詳解