前言
對(duì)于NSURLRequest,我們都很熟悉。在創(chuàng)建request時(shí),可以設(shè)置屬性cachePolicy,決定從本地還是網(wǎng)絡(luò)上獲取內(nèi)容。那么如果是從本地取的話,是從哪取呢?下面來(lái)簡(jiǎn)單聊一下。
NSURLCahe
NSURLCahe實(shí)現(xiàn)了response的緩存機(jī)制,將NSURLRequest和NSCachedURLResponse映射起來(lái)。默認(rèn)情況下,Memory cache=4M,Disk cache=20M??梢宰宇惢疦SURLCahe實(shí)現(xiàn)自己的緩存邏輯。
如果response的httpHeader里Cache-control/expires設(shè)置為可以被緩存,iOS會(huì)自動(dòng)的將其存到本地?cái)?shù)據(jù)庫(kù)中。路徑是沙盒路徑下Library/Caches/bundid/Cache.db。,對(duì)于webview的緩存,也一樣,因?yàn)樗彩怯玫腘SURLCache。

NSCachedURLResponse
NSCachedURLResponse是包含了NSURLResponse和緩存data的類。當(dāng)數(shù)據(jù)返回時(shí),將要緩存時(shí)會(huì)調(diào)這個(gè)方法。如果返回nil,則不緩存。原理如下。
- (nullable NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)cachedResponse;
if ([connection currentRequest].cachePolicy == NSURLRequestUseProtocolCachePolicy) {
NSDictionary *headers = [httpResponse allHeaderFields];
NSString *cacheControl = [headers valueForKey:@"Cache-Control"];
NSString *expires = [headers valueForKey:@"Expires"];
// don't cache
if (cacheControl == nil && expires == nil) {
return nil;
}
}
return cachedResponse;
}
- 判斷request的cachePolicy是否==NSURLRequestUseProtocolCachePolicy
- 取response的header,是否有cache-control和expire字段。
- 存在cache-control,緩存
- 存在expires,緩存
- cache-control和expire都沒(méi)有,認(rèn)為不緩存。因?yàn)樘O(píng)果沒(méi)有提及到服務(wù)端沒(méi)有返回expire時(shí),默認(rèn)的緩存時(shí)間是多少,所以直接做不緩存處理。
Cache.db
可以用MesaSQlite打開(kāi)Cache.db,其中包括4張表,我們主要關(guān)注3個(gè)。

也可以直接在命令行中sqlite3 dbpath,打開(kāi)數(shù)據(jù)庫(kù)。
sqlite3 ~/Library/Developer/CoreSimulator/Devices/9C84830D-9B7B-454A-A245-B25E6318B765/data/Containers/Data/Application/B85B7BF4-CEDE-42E2-A6B2-F1BB5214DBE6/Library/Caches/com.summer.test/Cache.db
查看表
sqlite> .tables
cfurl_cache_blob_data cfurl_cache_response
cfurl_cache_receiver_data cfurl_cache_schema_version
1.cfurl_cache_blob_data

entry_ID是主鍵,request_object請(qǐng)求對(duì)象,response_object響應(yīng)對(duì)象,都是BLOB類型。在MeaseSqlite中查看時(shí),數(shù)據(jù)不能完全顯示出來(lái)。不知道有什么方法可以直接查看blob。
執(zhí)行了一條sql,看到response_object的內(nèi)容如下:
sqlite> SELECT response_object FROM cfurl_cache_blob_data;
bplist00?WVersionUArray?
"#? __CFURLStringType\_CFURLString_Jhttp://static.m.yy.com/group1/M00/00/1D/dB95f1cZtpYAAAAAAAAFR2Vrq3A673.gif#A?????6?
只是可以大致知道包括了url,但其他的信息暫時(shí)不太清楚,如有知道的朋友,還請(qǐng)告知。
2.cfurl_cache_receiver_data

receiver_data存儲(chǔ)一些返回的數(shù)據(jù),如image,js,html,json等??梢宰孕胁榭?。
3.cfurl_cache_response

request_key:請(qǐng)求url
storage_policy:緩存策略
4.緩存的查找
- 在cfurl_cache_response中根據(jù)request_key(即url)查到entry_ID
- 在cfurl_cache_blob_data根據(jù)entry_ID找到response_object
- 在cfurl_cache_receiver_data中根據(jù)entry_ID找到receiver_data
最后用response_object和receiver_data拼裝NSCachedURLResponse。
NSURLResponse *urlResponse = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[[request allHTTPHeaderFields] objectForKey:@"Accept"] expectedContentLength:[(NSData *)response_object length] textEncodingName:nil];
NSCachedURLResponse *cachedURLResponse = [[NSCachedURLResponse alloc] initWithResponse:urlResponse data:receiver_data userInfo:nil storagePolicy:NSURLCacheStorageAllowed];
storagePolicy表明了object是否允許存儲(chǔ)。
typedef NS_ENUM(NSUInteger, NSURLCacheStoragePolicy)
{
NSURLCacheStorageAllowed, //內(nèi)存,磁盤(pán)都可以存
NSURLCacheStorageAllowedInMemoryOnly, //只能在內(nèi)存中
NSURLCacheStorageNotAllowed, //不允許
};
刪除緩存
執(zhí)行完這句后,表中的數(shù)據(jù)全部清空了。
[[NSURLCache sharedURLCache] removeAllCachedResponses];
后語(yǔ)
本文簡(jiǎn)單的說(shuō)明了下緩存的位置,及表結(jié)構(gòu)。若各路大蝦有更加深入的理解,歡迎提出。
遺留問(wèn)題:
1. 如何方便查看blob數(shù)據(jù)
2. response_object到底是神馬?
2017.1.6更新--解決遺留問(wèn)題
1、如何方便查看blob數(shù)據(jù)
無(wú)意中看到一篇博文,也說(shuō)到對(duì)blob數(shù)據(jù)的查看,作者發(fā)現(xiàn)blob中導(dǎo)出的txt數(shù)據(jù),都有相似的地方,以xxx開(kāi)頭,然后去google解法。剎那間我也想起,我所疑惑的問(wèn)題,是不是可以有相同的處理。
于是乎,喵了眼txt,全都是以plist00開(kāi)頭。搜了一下,發(fā)現(xiàn)原來(lái)是plist的二進(jìn)制文件。并且有方法可以直接轉(zhuǎn)成plist。這刻,????深深的體會(huì)到,會(huì)google真能解決不少難題。


命令也很簡(jiǎn)單:
plutil -convert binary1 -o result.plist 1.txt
廬山真面目終于要來(lái)了~

2、關(guān)于response_object
response_object也是blob格式的數(shù)據(jù),我試著用同樣的方式打開(kāi),果然還是個(gè)plist。內(nèi)容如下,字段意思都比較明了。

參考:
Taking Advantage of iOS5 Built-In HTTP DiskCache
Caching and NSURLConnection
Binary Property Lists