我讀過(guò)一些開(kāi)源項(xiàng)目的網(wǎng)絡(luò)請(qǐng)求緩存的代碼,基本上都是采用在本地存文件的方式進(jìn)行緩存。如果你打算在你的項(xiàng)目中加入網(wǎng)絡(luò)請(qǐng)求的緩存,可能你并不需要自己造一個(gè)輪子肖卧,了解一下NSURLCache
就足夠。
這是一個(gè)Apple已經(jīng)為你準(zhǔn)備好了的網(wǎng)絡(luò)請(qǐng)求緩存類掸鹅。網(wǎng)上對(duì)這個(gè)類的介紹并不多塞帐,并且有的文章講得很不詳細(xì)。希望這篇文章能讓你對(duì)NSURLCache
有一個(gè)比較詳細(xì)的了解巍沙。
緩存
首先葵姥,NSURLCache
提供的是內(nèi)存以及磁盤的綜合緩存機(jī)制。許多文章談到句携,使用NSURLCache
之前需要在AppDelegate
中緩存空間的設(shè)置:
- (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ùn)行如下代碼,可以看到:
print(NSURLCache.sharedURLCache().diskCapacity)
//output:
//10000000
print(NSURLCache.sharedURLCache().memoryCapacity)
//output:
//512000
也就是說(shuō)矮嫉,其實(shí)默認(rèn)就已經(jīng)設(shè)置好了512kb的內(nèi)存緩存空間削咆,以及10MB的磁盤緩存空間〈浪瘢可能你的代碼中并沒(méi)有寫任何與NSURLCache
有關(guān)的東西拨齐,但其實(shí)它已經(jīng)默默的開(kāi)始幫你進(jìn)行緩存了。
已經(jīng)緩存上了挺尿,但是怎么使用緩存呢奏黑?請(qǐng)繼續(xù)往下。
緩存策略
GET
不用多說(shuō)编矾,NSURLCache
只會(huì)對(duì)你的GET
請(qǐng)求進(jìn)行緩存熟史。
NSURLRequestCachePolicy
NSURLRequest
中有個(gè)屬性:
public var cachePolicy: NSURLRequestCachePolicy { get }
你可以通過(guò)這個(gè)屬性來(lái)設(shè)置請(qǐng)求的緩存策略,
public enum NSURLRequestCachePolicy : UInt {
case UseProtocolCachePolicy // 默認(rèn)值
case ReloadIgnoringLocalCacheData // 不使用緩存數(shù)據(jù)
case ReloadIgnoringLocalAndRemoteCacheData // Unimplemented
public static var ReloadIgnoringCacheData: NSURLRequestCachePolicy { get }
case ReturnCacheDataElseLoad // 無(wú)論緩存是否過(guò)期都是用緩存窄俏,沒(méi)有緩存就進(jìn)行網(wǎng)絡(luò)請(qǐng)求
case ReturnCacheDataDontLoad // 無(wú)論緩存是否過(guò)期都是用緩存蹂匹,沒(méi)有緩存也不會(huì)進(jìn)行網(wǎng)絡(luò)請(qǐng)求
case ReloadRevalidatingCacheData // Unimplemented
}
其實(shí)其他幾個(gè)值都比較好理解,唯獨(dú)默認(rèn)值UseProtocolCachePolicy
讓我不太懂凹蜈。
字面上的意思是按照協(xié)議的緩存策略進(jìn)行緩存限寞,那么這是什么協(xié)議呢?http協(xié)議仰坦。
服務(wù)器返回的響應(yīng)頭中會(huì)有這樣的字段:Cache-Control: max-age
or Cache-Control: s- maxage
履植,通過(guò)Cache-Control
來(lái)指定緩存策略,max-age
來(lái)表示過(guò)期時(shí)間悄晃。根據(jù)這些字段緩存機(jī)制再采用如下策略:
- 如果本地沒(méi)有緩存數(shù)據(jù)玫霎,則進(jìn)行網(wǎng)絡(luò)請(qǐng)求。
- 如果本地有緩存妈橄,并且緩存沒(méi)有失效庶近,則使用緩存。
- 如果緩存已經(jīng)失效眷蚓,則詢問(wèn)服務(wù)器數(shù)據(jù)是否改變鼻种,如果沒(méi)改變,依然使用緩存沙热,如果改變了則請(qǐng)求新數(shù)據(jù)叉钥。
- 如果沒(méi)有指定是否失效,那么系統(tǒng)將自己判斷緩存是否失效篙贸。(通常認(rèn)為是6-24小時(shí)的有效時(shí)間)
其實(shí)我以前對(duì)Cache-Control
之類的也并不太了解 T_T沼侣,自己默默的print了一下響應(yīng)頭,你可以看到:
print((response as? NSHTTPURLResponse)?.allHeaderFields)
//響應(yīng)頭中:Cache-Control: no-cache
這也就是為什么歉秫,雖然NSURLCache
一直在默默的緩存蛾洛,但是我并沒(méi)有感受到,當(dāng)然或許你那里不一樣雁芙。這個(gè)轧膘。(勘誤) 修正:no-cache表示不使用緩存,但是會(huì)緩存兔甘,no-store表示是不進(jìn)行緩存谎碍。no-cache
就表示不緩存
這里要額外提一句,看到網(wǎng)上有同學(xué)說(shuō)自己出現(xiàn)了某個(gè)請(qǐng)求數(shù)據(jù)一直使用緩存洞焙,沒(méi)有被更新蟆淀。這種情況可能就是服務(wù)器返回的Cache-Control
有誤拯啦。
打開(kāi)沙盒路徑下的Library/Caches 中,你可以看到緩存文件:
這可以說(shuō)明存在磁盤上的數(shù)據(jù)是存在數(shù)據(jù)庫(kù)里的熔任,性能不用擔(dān)心褒链。打開(kāi)數(shù)據(jù)庫(kù)文件就可以看到請(qǐng)求的數(shù)據(jù)。
在cfurl_cache_response
表中可以看到有一個(gè)字段是request_key
疑苔,通過(guò)里面的值可以推斷每一個(gè)response
是通過(guò)請(qǐng)求的url+參數(shù)
來(lái)作為key
儲(chǔ)存的甫匹。
當(dāng)然,經(jīng)過(guò)我的多次試驗(yàn)惦费,在Cache-Control: no-cache
的情況下兵迅,NSURLCache
也會(huì)進(jìn)行緩存,但是并不使用緩存數(shù)據(jù)薪贫。
總結(jié)一下:默認(rèn)情況下NSURLCache
的緩存策略是根據(jù)http協(xié)議來(lái)的恍箭,服務(wù)器通過(guò)Cache-Control: max-age
字段來(lái)告訴NSURLCache
是否需要緩存數(shù)據(jù)。
緩存封裝
如果你不打算采用http協(xié)議的緩存策略瞧省,依然可以使用NSURLCache
進(jìn)行緩存季惯。
public func cachedResponseForRequest(request: NSURLRequest) -> NSCachedURLResponse?
你可以通過(guò)這個(gè)方法,傳入請(qǐng)求臀突,來(lái)獲取緩存勉抓。NSCachedURLResponse
保存了上次請(qǐng)求的數(shù)據(jù)以及響應(yīng)頭。
public func storeCachedResponse(cachedResponse: NSCachedURLResponse, forRequest request: NSURLRequest)
NSURLSessionDelegate
協(xié)議中有如下方法候学,可以對(duì)即將緩存的數(shù)據(jù)進(jìn)行修改藕筋,添加userInfo,在代理方法中必須調(diào)用completionHandler,傳入將要緩存的數(shù)據(jù)梳码,如果傳nil則表示不緩存隐圾。
optional public func URLSession(session: NSURLSession,
dataTask: NSURLSessionDataTask,
willCacheResponse proposedResponse: NSCachedURLResponse,
completionHandler: (NSCachedURLResponse?) -> Void)
在Alamofire
中可以這樣寫:
Alamofire.Manager
.sharedInstance
.delegate
.dataTaskWillCacheResponse = { (session, task, cachedResponse) -> NSCachedURLResponse? in
var userInfo = [NSObject : AnyObject]()
// 設(shè)置userInfo
return NSCachedURLResponse(response: cachedResponse.response,
data: cachedResponse.data,
userInfo: userInfo,
storagePolicy: cachedResponse.storagePolicy)
}
參考
我也只是簡(jiǎn)單的對(duì)NSURLCache
進(jìn)行了介紹,需要深入了解的話大家還是需要拜讀一下文章掰茶,希望能給大家一些幫助: