iOS緩存配置申屹、AFN緩存配置

看了很多文章,大部分都是說緩存怎么讀取隧膏,而緩存的寫入都說是系統(tǒng)自動(dòng)寫入哗讥,說的不清楚。下面我就自己看過的文章和自己的實(shí)踐理解胞枕,寫一篇關(guān)于NSURLRequest杆煞、NSURLSession和AFNetworking緩存的介紹。

學(xué)習(xí)iOS的緩存主要有兩個(gè)方面腐泻,數(shù)據(jù)寫入緩存讀取决乎,下面先講緩存讀取

緩存讀取

只需要設(shè)置request請求的cachePolicy屬性,就可以控制緩存的讀取派桩,很簡單构诚。

  • 常用緩存策略
//使用協(xié)議緩存策略,也就是按照響應(yīng)頭的HTTP緩存字段來使用緩存
NSURLRequestUseProtocolCachePolicy
//忽略緩存
NSURLRequestReloadIgnoringLocalCacheData
//有緩存則讀緩存(就算緩存過期也讀取)铆惑,沒有則網(wǎng)絡(luò)加載
NSURLRequestReturnCacheDataElseLoad
//有緩存則讀緩存(就算緩存過期也讀取)范嘱,沒有則報(bào)錯(cuò)
NSURLRequestReturnCacheDataDontLoad
  • 下面有三種方法配置request的緩存策略,而且生效優(yōu)先級依次降低

1员魏、設(shè)置單個(gè)請求的緩存策略丑蛤,直接設(shè)置單個(gè)請求的緩存策略,其生效的優(yōu)先級是最高的撕阎,不會(huì)受到全局緩存配置的影響受裹。

NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;//本次請求忽略本地緩存 重新請求數(shù)據(jù)

2、設(shè)置NSURLSession緩存策略虏束,使用該session發(fā)出的所有請求都會(huì)服從該session的緩存策略名斟,其生效優(yōu)先級低于上面的單個(gè)請求配置

NSURLSessionConfiguration *confi = [NSURLSessionConfiguration defaultSessionConfiguration];
confi.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad;
NSURLSession *session = [NSURLSession sessionWithConfiguration:confi delegate:self 
                                                 delegateQueue:[NSOperationQueue mainQueue]];

3、設(shè)置AFNetworking緩存策略魄眉,生效優(yōu)先級低于上面的NSURLSession緩存配置

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

注意點(diǎn):如果允許使用緩存砰盐,在沒有網(wǎng)絡(luò)的情況下,倘若本地有緩存則會(huì)走成功的回調(diào)返回緩存數(shù)據(jù)坑律,不會(huì)走請求失敗的回調(diào)

緩存寫入

緩存的寫入所需的條件比較多

  • 系統(tǒng)默認(rèn)使用NSURLCache做緩存容器岩梳,首先我們可以按需設(shè)置NSURLCache的大小囊骤,我這里設(shè)置了4兆的內(nèi)存20兆的磁盤空間做緩存。如果不需要緩存那么直接設(shè)置空間為0.
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 
                                            diskCapacity:20 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];    //設(shè)置共享緩存容器
  • 緩存在寫入前會(huì)調(diào)用NSURLSession的willCacheResponse這個(gè)代理方法冀值,并且只有將response傳給completionHandler()之后系統(tǒng)才會(huì)緩存該響應(yīng)也物,如果傳入nil則表示不緩存該響應(yīng)。我們可以在這個(gè)方法里修改響應(yīng)信息列疗,然后保存修改之后的響應(yīng)信息滑蚯。(不只是GET請求,POST請求也能觸發(fā)代理方法抵栈,保存響應(yīng))
  • 響應(yīng)信息會(huì)被緩存下來的先決條件:首先要滿足willCacheResponse代理方法的觸發(fā)條件(如果這個(gè)代理方法都不能觸發(fā)告材,那么緩存的寫入也無從談起)。然后將需要緩存的響應(yīng)傳給代理方法的completionHandler()進(jìn)行保存古劲,如果傳入nil則表示不緩存斥赋。
    注意:如果設(shè)置共享緩存空間為0,那么也不會(huì)緩存響應(yīng)信息

只有滿足以下所有條件時(shí)才會(huì)觸發(fā)willCacheResponse代理方法:
1产艾、請求是針對HTTP或HTTPS URL(或你自己的支持緩存的自定義網(wǎng)絡(luò)協(xié)議)疤剑。
2、請求成功(狀態(tài)碼在200-299范圍內(nèi))闷堡。
3隘膘、返回的響應(yīng)數(shù)據(jù)來自服務(wù)器,而不是來自本地緩存杠览。(廢話弯菊,本地緩存不會(huì)再緩存一遍)
下面兩個(gè)條件是我從其他文章看到的,經(jīng)過測試發(fā)現(xiàn)并不需要
//4倦零、session會(huì)話配置的緩存策略允許緩存。(這個(gè)條件好像有問題吨悍,會(huì)話配置只決定是否使用緩存扫茅,而不決定緩存的寫入)
//5、NSURLRequest對象的緩存策略(如果適用)允許緩存育瓜。(這也是控制響應(yīng)的寫入)
6葫隙、服務(wù)器響應(yīng)中的緩存相關(guān)頭(如果存在)允許緩存。也就是響應(yīng)頭中的HTTP緩存字段(這里一下解釋不清躏仇,請自行查看http的緩存相關(guān)字段)
7恋脚、響應(yīng)大小足夠小,可以合理地放入緩存中焰手。 (例如糟描,如果您提供磁盤緩存曹货,則響應(yīng)不得超過磁盤緩存大小的5%熏迹。)
注:如果代理實(shí)現(xiàn)此方法willCacheResponse,則該代理方法中必須調(diào)用completionHandler完成處理程序吻育,否則應(yīng)用程序會(huì)泄漏內(nèi)存。

  • 對willCacheResponse這個(gè)代理方法的一些使用
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask 
    willCacheResponse:(NSCachedURLResponse *)proposedResponse 
    completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {

    //這里可以修改HTTP的緩存字段
    NSURLResponse *response = proposedResponse.response;
    NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse*)response;
    NSDictionary *headers = HTTPResponse.allHeaderFields;
    NSCachedURLResponse *cachedResponse;
    //修改Cache-Control字段的值
    NSMutableDictionary *modifiedHeaders = headers.mutableCopy;
    [modifiedHeaders setObject:@"max-age=10" forKey:@"Cache-Control"];
    NSHTTPURLResponse * modifiedResponse;
    modifiedResponse = [[NSHTTPURLResponse alloc] initWithURL:HTTPResponse.URL 
                            statusCode:HTTPResponse.statusCode HTTPVersion:@"HTTP/1.1" 
                            headerFields:modifiedHeaders];
    cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:modifiedResponse 
                            data:proposedResponse.data
                            userInfo:proposedResponse.userInfo 
                            storagePolicy:proposedResponse.storagePolicy];

    //將修改后的響應(yīng)信息交給該block執(zhí)行见间,該block就會(huì)保存該響應(yīng)聊闯,當(dāng)然了也可以不修改響應(yīng)
    completionHandler(cachedResponse);   //返回nil則表示不緩存響應(yīng)
}

AFN緩存

AFN默認(rèn)已經(jīng)實(shí)現(xiàn)了willCacheResponse代理方法,只要滿足這個(gè)代理方法的觸發(fā)條件米诉,那么該響應(yīng)就會(huì)被緩存到本地菱蔬。
并且如果在緩存響應(yīng)之前想要修改這個(gè)響應(yīng),可以設(shè)置AFN的一個(gè)block史侣,在這個(gè)block中修改響應(yīng)信息拴泌,如下。(當(dāng)然也可以在這個(gè)block中設(shè)置過濾抵窒,根據(jù)請求信息過濾掉不想緩存的響應(yīng))

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, 
           NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
    //修改響應(yīng)信息
    NSURLResponse *response = proposedResponse.response;
    NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse*)response;
    NSDictionary *headers = HTTPResponse.allHeaderFields;
    NSCachedURLResponse *cachedResponse;
    //這里就可以針對Cache-Control進(jìn)行更改弛针,然后直接我們通過某方法獲取NSCachedURLResponse的時(shí)候就可以先去判斷下頭域信息
    NSMutableDictionary *modifiedHeaders = headers.mutableCopy;
    [modifiedHeaders setObject:@"max-age=1000" forKey:@"Cache-Control"];
    NSHTTPURLResponse *modifiedResponse = [[NSHTTPURLResponse alloc] initWithURL:HTTPResponse.URL statusCode:
                                                   HTTPResponse.statusCode HTTPVersion:@"HTTP/1.1" headerFields:modifiedHeaders];
    cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:modifiedResponse data:proposedResponse.data
                                                 userInfo:proposedResponse.userInfo storagePolicy:proposedResponse.storagePolicy];
            
    return cachedResponse;      //返回修改后的響應(yīng)
}];

如果想要AFN使用已經(jīng)保存好的響應(yīng),那么直接設(shè)置AFN的緩存策略允許使用緩存即可李皇,幾種緩存使用策略上面已經(jīng)介紹過了

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

通常在實(shí)際應(yīng)用中需要根據(jù)不同的網(wǎng)絡(luò)狀態(tài)設(shè)置不同的緩存策略削茁,一般對于JSON數(shù)據(jù)來說,因?yàn)樗ǔJ欠琴Y源文件掉房,可能會(huì)經(jīng)常變動(dòng)茧跋,所以在有網(wǎng)的情況下需要禁用緩存來實(shí)時(shí)刷新,在無網(wǎng)的情況下才使用緩存數(shù)據(jù)卓囚。通绸迹可以配合AFN的網(wǎng)絡(luò)監(jiān)聽一起使用,以達(dá)到在不同的網(wǎng)絡(luò)環(huán)境下使用不同的緩存策略的效果哪亿。

//使用AFN框架來檢測網(wǎng)絡(luò)狀態(tài)的改變
-(void)AFNReachability{
    /*
     AFNetworkReachabilityStatusUnknown     = 未知
     AFNetworkReachabilityStatusNotReachable   = 沒有網(wǎng)絡(luò)
     AFNetworkReachabilityStatusReachableViaWWAN = 3G
     AFNetworkReachabilityStatusReachableViaWiFi = WIFI
     */
    [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                self.manager.requestSerializer.cachePolicy = NSURLRequestReturnCacheDataDontLoad;
                break;
            case AFNetworkReachabilityStatusNotReachable:
                self.manager.requestSerializer.cachePolicy = NSURLRequestReturnCacheDataDontLoad;
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                self.manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                self.manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
                break;
            default:
                self.manager.requestSerializer.cachePolicy = NSURLRequestReturnCacheDataDontLoad;
                break;
        }
    }];
    //開始監(jiān)聽
    [manager startMonitoring];
}

GET粥烁、POST使用緩存時(shí)的區(qū)別

系統(tǒng)緩存都是存放在以下路徑的數(shù)據(jù)庫文件中,注意顯示隱藏文件蝇棉,因?yàn)槲募A的名字是AppID讨阻,有些AppID是以"."點(diǎn)開頭的,系統(tǒng)會(huì)將以點(diǎn)開頭的文件當(dāng)做隱藏文件

數(shù)據(jù)庫文件中就存放著我們的緩存數(shù)據(jù)篡殷,并且以請求的URL為鍵值進(jìn)行保存钝吮,讀取緩存時(shí)也是系統(tǒng)自動(dòng)通過URL讀取。當(dāng)請求沒有參數(shù)或者參數(shù)值固定不變時(shí)板辽,GET和POST請求都能夠正確讀到緩存奇瘦,但是當(dāng)請求有參數(shù),并且參數(shù)的值不固定時(shí)劲弦,POST使用緩存就有問題了耳标,你會(huì)發(fā)現(xiàn)無論參數(shù)值如何變化,獲取到的緩存數(shù)據(jù)都是一樣的邑跪。這是因?yàn)镻OST請求的參數(shù)沒有拼接在URL后面麻捻,所以導(dǎo)致參數(shù)值無論怎么變纲仍,URL始終是一樣的,以URL為鍵值獲取的緩存數(shù)據(jù)也是一樣(因?yàn)閁RL一樣贸毕,所以系統(tǒng)每次請求都會(huì)覆蓋上一次緩存)郑叠。而GET請求不一樣,他的參數(shù)拼接在URL后面明棍,所以當(dāng)參數(shù)值變化時(shí)URL也隨之改變乡革,不同的參數(shù)值唯一確定不同的一個(gè)URL,所以讀取的緩存也就一一對應(yīng)摊腋,不會(huì)重復(fù)沸版。

總結(jié)一下:

  • 請求沒有參數(shù)或者參數(shù)值固定不變,那么GET和POST都可以正常使用緩存
  • 請求有參數(shù)且參數(shù)值會(huì)變化兴蒸,那么GET可以正常使用緩存视粮,POST不可以

參考文章
iOS網(wǎng)絡(luò)——NSURLCache設(shè)置網(wǎng)絡(luò)請求緩存
NSURLSession發(fā)送請求通過NSURLCache 做的緩存
NSURLSession 所有的都在這里(二)
https://www.cnblogs.com/rainySue/p/huan-cun.html#toc_11

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市橙凳,隨后出現(xiàn)的幾起案子蕾殴,更是在濱河造成了極大的恐慌,老刑警劉巖岛啸,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钓觉,死亡現(xiàn)場離奇詭異,居然都是意外死亡坚踩,警方通過查閱死者的電腦和手機(jī)荡灾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞬铸,“玉大人批幌,你說我怎么就攤上這事∩そ冢” “怎么了荧缘?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赦政。 經(jīng)常有香客問我胜宇,道長耀怜,這世上最難降的妖魔是什么恢着? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮财破,結(jié)果婚禮上掰派,老公的妹妹穿的比我還像新娘。我一直安慰自己左痢,他們只是感情好靡羡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布系洛。 她就那樣靜靜地躺著,像睡著了一般略步。 火紅的嫁衣襯著肌膚如雪描扯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天趟薄,我揣著相機(jī)與錄音绽诚,去河邊找鬼。 笑死杭煎,一個(gè)胖子當(dāng)著我的面吹牛恩够,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羡铲,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蜂桶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了也切?” 一聲冷哼從身側(cè)響起扑媚,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贾费,沒想到半個(gè)月后钦购,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褂萧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年押桃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片导犹。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唱凯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谎痢,到底是詐尸還是另有隱情磕昼,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布节猿,位于F島的核電站票从,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏滨嘱。R本人自食惡果不足惜峰鄙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望太雨。 院中可真熱鬧吟榴,春花似錦、人聲如沸囊扳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狭瞎,卻和暖如春细移,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背熊锭。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工葫哗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人球涛。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓劣针,卻偏偏與公主長得像,于是被迫代替她去往敵國和親亿扁。 傳聞我的和親對象是個(gè)殘疾皇子捺典,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

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