iOS網(wǎng)絡(luò)請(qǐng)求緩存:NSURLCache詳解

我讀過(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é)議仰坦。

詳細(xì):RFC 2616, Section 13

服務(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就表示不緩存轧膘。(勘誤) 修正:no-cache表示不使用緩存,但是會(huì)緩存兔甘,no-store表示是不進(jìn)行緩存谎碍。

這里要額外提一句,看到網(wǎng)上有同學(xué)說(shuō)自己出現(xiàn)了某個(gè)請(qǐng)求數(shù)據(jù)一直使用緩存洞焙,沒(méi)有被更新蟆淀。這種情況可能就是服務(wù)器返回的Cache-Control有誤拯啦。

打開(kāi)沙盒路徑下的Library/Caches 中,你可以看到緩存文件:

沙盒中的緩存文件.png

這可以說(shuō)明存在磁盤上的數(shù)據(jù)是存在數(shù)據(jù)庫(kù)里的熔任,性能不用擔(dān)心褒链。打開(kāi)數(shù)據(jù)庫(kù)文件就可以看到請(qǐng)求的數(shù)據(jù)。

緩存數(shù)據(jù).png

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)
}

參考

我的blog:Roxily's Blog

我也只是簡(jiǎn)單的對(duì)NSURLCache進(jìn)行了介紹,需要深入了解的話大家還是需要拜讀一下文章掰茶,希望能給大家一些幫助:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暇藏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子濒蒋,更是在濱河造成了極大的恐慌盐碱,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沪伙,死亡現(xiàn)場(chǎng)離奇詭異瓮顽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)围橡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門暖混,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人翁授,你說(shuō)我怎么就攤上這事拣播×肋洌” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵贮配,是天一觀的道長(zhǎng)谍倦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)牧嫉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任减途,我火速辦了婚禮酣藻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳍置。我一直安慰自己辽剧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布税产。 她就那樣靜靜地躺著怕轿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辟拷。 梳的紋絲不亂的頭發(fā)上撞羽,一...
    開(kāi)封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音衫冻,去河邊找鬼诀紊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛隅俘,可吹牛的內(nèi)容都是我干的邻奠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼为居,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼碌宴!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蒙畴,我...
    開(kāi)封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贰镣,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后膳凝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體八孝,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年鸠项,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了干跛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祟绊,死狀恐怖楼入,靈堂內(nèi)的尸體忽然破棺而出哥捕,到底是詐尸還是另有隱情,我是刑警寧澤嘉熊,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布遥赚,位于F島的核電站,受9級(jí)特大地震影響阐肤,放射性物質(zhì)發(fā)生泄漏凫佛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一孕惜、第九天 我趴在偏房一處隱蔽的房頂上張望愧薛。 院中可真熱鬧,春花似錦衫画、人聲如沸毫炉。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瞄勾。三九已至,卻和暖如春弥激,著一層夾襖步出監(jiān)牢的瞬間进陡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工微服, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留四濒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓职辨,卻偏偏與公主長(zhǎng)得像盗蟆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舒裤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容