NSURLCache
NSURLCache 為您的應(yīng)用的 URL 請(qǐng)求提供了內(nèi)存中以及磁盤上的綜合緩存機(jī)制幢泼。 作為基礎(chǔ)類庫(kù) URL 加載系統(tǒng) 的一部分,任何通過 NSURLConnection 加載的請(qǐng)求都將被 NSURLCache 處理根竿。
網(wǎng)絡(luò)緩存減少了需要向服務(wù)器發(fā)送請(qǐng)求的次數(shù),同時(shí)也提升了離線或在低速網(wǎng)絡(luò)中使用應(yīng)用的體驗(yàn)。
當(dāng)一個(gè)請(qǐng)求完成下載來自服務(wù)器的回應(yīng)忿偷,一個(gè)緩存的回應(yīng)將在本地保存。下一次同一個(gè)請(qǐng)求再發(fā)起時(shí)臊泌,本地保存的回應(yīng)就會(huì)馬上返回鲤桥,不需要連接服務(wù)器。NSURLCache 會(huì) 自動(dòng) 且 透明 地返回回應(yīng)渠概。
為了好好利用 NSURLCache茶凳,你需要初始化并設(shè)置一個(gè)共享的 URL 緩存。在 iOS 中這項(xiàng)工作需要在 -application:didFinishLaunchingWithOptions: 完成播揪,而 OS X 中是在 –applicationDidFinishLaunching::
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil]; [NSURLCache setSharedURLCache:URLCache];}
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
緩存策略由請(qǐng)求(客戶端)和回應(yīng)(服務(wù)端)分別指定贮喧。理解這些策略以及它們?nèi)绾蜗嗷ビ绊懀菫槟膽?yīng)用程序找到最佳行為的關(guān)鍵猪狈。
NSURLRequestCachePolicy 緩存策略
NSURLRequest 有個(gè) cachePolicy 屬性箱沦,它根據(jù)以下常量指定了請(qǐng)求的緩存行為:
NSURLRequestUseProtocolCachePolicy: 對(duì)特定的 URL 請(qǐng)求使用網(wǎng)絡(luò)協(xié)議中實(shí)現(xiàn)的緩存邏輯。這是默認(rèn)的策略雇庙。 NSURLRequestReloadIgnoringLocalCacheData:數(shù)據(jù)需要從原始地址加載谓形。不使用現(xiàn)有緩存。 NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不僅忽略本地緩存疆前,同時(shí)也忽略代理服務(wù)器或其他中間介質(zhì)目前已有的寒跳、協(xié)議允許的緩存。 NSURLRequestReturnCacheDataElseLoad:無(wú)論緩存是否過期竹椒,先使用本地緩存數(shù)據(jù)童太。如果緩存中沒有請(qǐng)求所對(duì)應(yīng)的數(shù)據(jù),那么從原始地址加載數(shù)據(jù)。 NSURLRequestReturnCacheDataDontLoad:無(wú)論緩存是否過期书释,先使用本地緩存數(shù)據(jù)翘贮。如果緩存中沒有請(qǐng)求所對(duì)應(yīng)的數(shù)據(jù),那么放棄從原始地址加載數(shù)據(jù)征冷,請(qǐng)求視為失斣裣ァ(即:“離線”模式)。 NSURLRequestReloadRevalidatingCacheData:從原始地址確認(rèn)緩存數(shù)據(jù)的合法性后, 必須得得到服務(wù)端確認(rèn)有效才使用(貌似是NSURLRequestUseProtocolCachePolicy 中的一種情況)检激,緩存數(shù)據(jù)就可以使用肴捉,否則從原始地址加載。
注: 1.URL Loading System默認(rèn)只支持如下5中協(xié)議: 其中只有http://和https://才有緩存策略. (1) http:// (2) https:// (3) ftp:// (4) file:// (5) data://
2.NSURLRequestReloadIgnoringLocalAndRemoteCacheData 和 NSURLRequestReloadRevalidatingCacheData 根本沒有實(shí)現(xiàn)叔收!
關(guān)于NSURLRequestCachePolicy齿穗,以下才是你實(shí)際需要了解的東西:
HTTP 緩存語(yǔ)義
因?yàn)?NSURLConnection 被設(shè)計(jì)成支持多種協(xié)議——包括 FTP、HTTP饺律、HTTPS——所以 URL 加載系統(tǒng)用一種協(xié)議無(wú)關(guān)的方式指定緩存窃页。為了本文的目的,緩存用術(shù)語(yǔ) HTTP 語(yǔ)義來解釋复濒。
HTTP 請(qǐng)求和回應(yīng)用 headers 來交換元數(shù)據(jù)脖卖,如字符編碼、MIME 類型和緩存指令等巧颈。
Request Cache Headers
在默認(rèn)情況下畦木,NSURLRequest 會(huì)用當(dāng)前時(shí)間決定是否返回緩存的數(shù)據(jù)。為了更精確地控制砸泛,允許使用以下請(qǐng)求頭:
If-Modified-Since - 這個(gè)請(qǐng)求頭與 Last-Modified 回應(yīng)頭相對(duì)應(yīng)十籍。把這個(gè)值設(shè)為同一終端最后一次請(qǐng)求時(shí)返回的 Last-Modified 字段的值。 If-None-Match - 這個(gè)請(qǐng)求頭與與 Etag 回應(yīng)頭相對(duì)應(yīng)唇礁。使用同一終端最后一次請(qǐng)求的 Etag 值勾栗。
Response Cache Headers
NSHTTPURLResponse 包含多個(gè) HTTP 頭,當(dāng)然也包括以下指令來說明回應(yīng)應(yīng)當(dāng)如何緩存:
Cache-Control - 這個(gè)頭必須由服務(wù)器端指定以開啟客戶端的 HTTP 緩存功能盏筐。這個(gè)頭的值可能包含 max-age(緩存多久)围俘,是公共 public 還是私有 private,或者不緩存 no-cache 等信息琢融。詳情請(qǐng)參閱 Cache-Control section of RFC 2616楷拳。 除了 Cache-Control 以外,服務(wù)器也可能發(fā)送一些附加的頭用于根據(jù)需要有條件地請(qǐng)求:
Last-Modified - 這個(gè)頭的值表明所請(qǐng)求的資源上次修改的時(shí)間吏奸。例如,一個(gè)客戶端請(qǐng)求最近照片的時(shí)間線陶耍,/photos/timeline奋蔚,Last-Modified 的值可以是最近一張照片的拍攝時(shí)間。 Etag - 這是 “entity tag” 的縮寫,它是一個(gè)表示所請(qǐng)求資源的內(nèi)容的標(biāo)識(shí)符泊碑。在實(shí)踐中坤按,Etag 的值可以是類似于資源的 MD5 之類的東西。這對(duì)于那些動(dòng)態(tài)生成的馒过、可能沒有明顯的 Last-Modified 值的資源非常有用臭脓。
NSURLConnectionDelegate
一旦收到了服務(wù)器的回應(yīng),NSURLConnection 的代理就有機(jī)會(huì)在 -connection:willCacheResponse: 中指定緩存數(shù)據(jù)腹忽。
NSCachedURLResponse 是個(gè)包含 NSURLResponse 以及它對(duì)應(yīng)的緩存中的 NSData 的類来累。
在 -connection:willCacheResponse: 中,cachedResponse 對(duì)象會(huì)根據(jù) URL 連接返回的結(jié)果自動(dòng)創(chuàng)建窘奏。因?yàn)?NSCachedURLResponse 沒有可變部分嘹锁,為了改變 cachedResponse 中的值必須構(gòu)造一個(gè)新的對(duì)象,把改變過的值傳入 –initWithResponse:data:userInfo:storagePolicy:着裹,例如:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{ NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy]; NSMutableData *mutableData = [[cachedResponse data] mutableCopy]; NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly; // ... return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response] data:mutableData userInfo:mutableUserInfo storagePolicy:storagePolicy];}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
如果 -connection:willCacheResponse: 返回 nil领猾,回應(yīng)將不會(huì)緩存。
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse{ return nil;}
1
2
3
4
5
1
2
3
4
5
如果不實(shí)現(xiàn)此方法骇扇,NSURLConnection 就簡(jiǎn)單地使用本來要傳入 -connection:willCacheResponse: 的那個(gè)緩存對(duì)象摔竿,所以除非你需要改變一些值或者阻止緩存,否則這個(gè)代理方法不必實(shí)現(xiàn)少孝。
NSURLCache & NSCachedURLResponse常用方法
NSURLCache
1.初始化相關(guān)的幾個(gè)方法:sharedURLCache继低;setSharedURLCache;initWithMemoryCapacity sharedURLCache方法返回一個(gè)NSURLCache實(shí)例韭山。 默認(rèn)情況下郁季,內(nèi)存是4M,4* 1024 * 1024钱磅;Disk為20M梦裂,20 * 1024 * 1024;路徑在(NSHomeDirectory)/Library/Caches/(current application name, [[NSProcessInfo processInfo] processName]) setSharedURLCache可以通過這個(gè)方法來改變默認(rèn)的NSURLCache盖淡。通過initWithMemoryCapacity來定制自己的NSURLCache年柠。
2.cache使用相關(guān)的幾個(gè)方法:cachedResponseForRequest;storeCachedResponse褪迟;removeCachedResponseForRequest; removeAllCachedResponses - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request; 如果對(duì)應(yīng)的NSURLRequest沒有cached的response那么返回nil - (void)storeCachedResponse:(NSCachedURLResponse )cachedResponse forRequest:(NSURLRequest)request; 為特定的NSURLRequest做cache - (void)removeCachedResponseForRequest:(NSURLRequest *)request; 移除特定NSURLRequest的cache - (void)removeAllCachedResponses; 移除所有的cache
3.property方法 - (NSUInteger)memoryCapacity; - (NSUInteger)diskCapacity; - (void)setMemoryCapacity:(NSUInteger)memoryCapacity; 可能會(huì)導(dǎo)致內(nèi)存中的內(nèi)存被截?cái)?- (void)setDiskCapacity:(NSUInteger)diskCapacity; - (NSUInteger)currentMemoryUsage; - (NSUInteger)currentDiskUsage;
4.Misc a. NSURLCache在每個(gè)UIWebView的的NSURLRequest請(qǐng)求中都會(huì)被調(diào)用味赃。 b. ios設(shè)備上NSURLCache默認(rèn)只能進(jìn)行內(nèi)存緩存掀抹。可以通過子類化NSURLCache來實(shí)現(xiàn)自定義的版本從而實(shí)現(xiàn)在DISK上緩存內(nèi)容心俗。 c. 需要重寫cachedResponseForRequest傲武,這個(gè)會(huì)在請(qǐng)求發(fā)送前會(huì)被調(diào)用蓉驹,從中我們可以判定是否針對(duì)此NSURLRequest返回本地?cái)?shù)據(jù)。 d. 如果本地沒有緩存就調(diào)用下面這條語(yǔ)句:return [super cachedResponseForRequest:request];
NSCachedURLResponse
包裝了一下系統(tǒng)緩存機(jī)制的對(duì)象揪利,保持了緩存對(duì)象的個(gè)性和特性态兴。 1.NSURLCacheStoragePolicy 緩存策略有三種 enum { NSURLCacheStorageAllowed, NSURLCacheStorageAllowedInMemoryOnly, NSURLCacheStorageNotAllowed, }; 默認(rèn)是第一種。不過在iOS的上官方文檔上有這么一個(gè)解釋: Important: iOS ignores this cache policy, and instead treats it asNSURLCacheStorageAllowedInMemoryOnly. 也就是說iOS上只有內(nèi)存緩存疟位,沒有磁盤緩存瞻润。
2.構(gòu)造方法 - (id)initWithResponse:(NSURLResponse *)response data:(NSData *)data; - (id)initWithResponse:(NSURLResponse *)response data:(NSData *)data userInfo:(NSDictionary *)userInfo storagePolicy:(NSURLCacheStoragePolicy)storagePolicy;
3.Open API - (NSURLResponse *)response; - (NSData *)data; - (NSDictionary *)userInfo; - (NSURLCacheStoragePolicy)storagePolicy;
注意事項(xiàng)
正如它那個(gè)毫無(wú)關(guān)系但是名字相近的小伙伴 NSCache 一樣,NSURLCache 也是有一些特別的甜刻。
Peter Steinberger 關(guān)于這個(gè)主題寫了一篇優(yōu)秀的文章绍撞,在深入研究?jī)?nèi)部細(xì)節(jié)后實(shí)現(xiàn)他自己的 NSURLCache 子類。NSURLCache 提醒著我們熟悉我們正在操作的系統(tǒng)是多么地重要罢吃。
Daniel Pasco 在 Black Pixel 上的另一篇文章 描述了一些與服務(wù)器通信時(shí)不設(shè)置緩存頭的意外的默認(rèn)行為楚午。
無(wú)數(shù)開發(fā)者嘗試自己做一個(gè)簡(jiǎn)陋而脆弱的系統(tǒng)來實(shí)現(xiàn)網(wǎng)絡(luò)緩存的功能,殊不知 NSURLCache 只要兩行代碼就能搞定且好上100倍尿招。甚至更多開發(fā)者根本不知道網(wǎng)絡(luò)緩存的好處矾柜,也從未嘗試過,導(dǎo)致他們的應(yīng)用向服務(wù)器作了無(wú)數(shù)不必要的網(wǎng)絡(luò)請(qǐng)求就谜。
所以如果你想看到世界的變化怪蔑,你想確保你有程序總以正確的方式開啟,在 -application:didFinishLaunchingWithOptions: 設(shè)置一個(gè)共享的 NSURLCache 吧丧荐。NSCache是系統(tǒng)提供的一種類似于集合(NSMutableDictionary)的緩存缆瓣,它與集合的不同如下:
NSCache具有自動(dòng)刪除的功能,以減少系統(tǒng)占用的內(nèi)存虹统;
NSCache是線程安全的弓坞,不需要加線程鎖;
鍵對(duì)象不會(huì)像 NSMutableDictionary 中那樣被復(fù)制车荔。(鍵不需要實(shí)現(xiàn) NSCopying 協(xié)議)渡冻。
NSCache的屬性以及方法介紹:
@property NSUInteger totalCostLimit;
設(shè)置緩存占用的內(nèi)存大小,并不是一個(gè)嚴(yán)格的限制忧便,當(dāng)總數(shù)超過了totalCostLimit設(shè)定的值族吻,系統(tǒng)會(huì)清除一部分緩存,直至總消耗低于totalCostLimit的值珠增。
@property NSUInteger countLimit;
設(shè)置緩存對(duì)象的大小超歌,這也不是一個(gè)嚴(yán)格的限制。
- (id)objectForKey:(id)key;
獲取緩存對(duì)象蒂教,基于key-value對(duì)
- (void)setObject:(id)obj forKey:(id)key; // 0 cost
存儲(chǔ)緩存對(duì)象巍举,考慮緩存的限制屬性;
- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g;
存儲(chǔ)緩存對(duì)象凝垛,cost是提前知道該緩存對(duì)象占用的字節(jié)數(shù)懊悯,也會(huì)考慮緩存的限制屬性简烘,建議直接使用
- (void)setObject:(id)obj forKey:(id)key;
NSCacheDelegate代理
代理屬性聲明如下:
@property (assign) id<NSCacheDelegate>delegate;
實(shí)現(xiàn)了NSCacheDelegate代理的對(duì)象,在緩存對(duì)象即將被清理的時(shí)候定枷,系統(tǒng)回調(diào)代理方法如下:
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
第一個(gè)參數(shù)是當(dāng)前緩存(NSCache),不要修改該對(duì)象届氢;
第二個(gè)參數(shù)是當(dāng)前將要被清理的對(duì)象欠窒,如果需要存儲(chǔ)該對(duì)象,可以在此操作(存入Sqlite or CoreData);
該代理方法的調(diào)用會(huì)在緩存對(duì)象即將被清理的時(shí)候調(diào)用退子,如下場(chǎng)景會(huì)調(diào)用:
1. - (void)removeObjectForKey:(id)key; 手動(dòng)刪除對(duì)象岖妄;
2. 緩存對(duì)象超過了NSCache的屬性限制;(countLimit 和 totalCostLimit )
3. App進(jìn)入后臺(tái)會(huì)調(diào)用寂祥;
4. 系統(tǒng)發(fā)出內(nèi)存警告荐虐;
NSDiscardableContent協(xié)議
NSDiscardableContent是一個(gè)協(xié)議,實(shí)現(xiàn)這個(gè)協(xié)議的目的是為了讓我們的對(duì)象在不被使用時(shí)丸凭,可以將其丟棄福扬,以讓程序占用更少的內(nèi)存。
一個(gè)NSDiscardableContent對(duì)象的生命周期依賴于一個(gè)“counter”變量惜犀。一個(gè)NSDiscardableContent對(duì)象實(shí)際是一個(gè)可清理內(nèi)存塊铛碑,這個(gè)內(nèi)存記錄了對(duì)象當(dāng)前是否被其它對(duì)象使用。如果這塊內(nèi)存正在被讀取虽界,或者仍然被需要汽烦,則它的counter變量是大于或等于1的;當(dāng)它不再被使用時(shí)莉御,就可以丟棄撇吞,此時(shí)counter變量將等于0。當(dāng)counter變量等于0時(shí)礁叔,如果當(dāng)前時(shí)間點(diǎn)內(nèi)存比較緊張的話牍颈,內(nèi)存塊就可能被丟棄。這點(diǎn)類似于MRC&ARC晴圾,對(duì)象內(nèi)存回收機(jī)制颂砸。
- (void)discardContentIfPossible
當(dāng)counter等于0的時(shí)候,為了丟棄這些對(duì)象死姚,會(huì)調(diào)用這個(gè)方法人乓。
默認(rèn)情況下,NSDiscardableContent對(duì)象的counter變量初始值為1都毒,以確保對(duì)象不會(huì)被內(nèi)存管理系統(tǒng)立即釋放色罚。
- (BOOL)beginContentAccess (counter++)
調(diào)用該方法,對(duì)象的counter會(huì)加1账劲;
與beginContentAccess相對(duì)應(yīng)的是endContentAccess戳护。如果可丟棄內(nèi)存不再被訪問時(shí)調(diào)用金抡。其聲明如下:
- (void)endContentAccess (counter--)
該方法會(huì)減少對(duì)象的counter變量,通常是讓對(duì)象的counter值變回為0腌且,這樣在對(duì)象的內(nèi)容不再被需要時(shí)梗肝,就要以將其丟棄。
NSCache類提供了一個(gè)屬性铺董,來標(biāo)識(shí)緩存是否自動(dòng)舍棄那些內(nèi)存已經(jīng)被丟棄的對(duì)象(默認(rèn)該屬性為YES)巫击,其聲明如下:
@property BOOL evictsObjectsWithDiscardedContent
如果設(shè)置為YES,則在對(duì)象的內(nèi)存被丟棄時(shí)舍棄對(duì)象精续。
個(gè)人建議:如果需要使用緩存坝锰,直接用系統(tǒng)的NSCache就OK了,不要做死重付。
2.代碼演示:
先定義緩存池,并懶加載初始化:
#import "ViewController.h"
@interface ViewController ()<NSCacheDelegate>
// 定義緩存池
@property (nonatomic, strong) NSCache *cache;
@end
@implementation ViewController
- (NSCache *)cache {
if (_cache == nil) {
_cache = [[NSCache alloc] init];
// 緩存中總共可以存儲(chǔ)多少條
_cache.countLimit = 5;
// 緩存的數(shù)據(jù)總量為多少
_cache.totalCostLimit = 1024 * 5;
}
return _cache;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor=[UIColor whiteColor];
//添加緩存數(shù)據(jù)
for (int i = 0; i < 10; i++) {
[self.cache setObject:[NSString stringWithFormat:@"hello %d",i] forKey:[NSString stringWithFormat:@"h%d",i]];
NSLog(@"添加 %@",[NSString stringWithFormat:@"hello %d",i]);
}
//輸出緩存中的數(shù)據(jù)
for (int i = 0; i < 10; i++) {
NSLog(@"%@",[self.cache objectForKey:[NSString stringWithFormat:@"h%d",i]]);
}
}
控制臺(tái)輸出結(jié)果為:
**通過輸出結(jié)果可以看出: **
1.當(dāng)我們使用NSCache來創(chuàng)建緩存池的時(shí)候,我們可以很靈活的設(shè)置緩存的限額,2.當(dāng)程序中的個(gè)數(shù)超過我們的限額的時(shí)候,會(huì)先移除最先創(chuàng)建的3.如果已經(jīng)移除了,那么當(dāng)我們輸出緩存中的數(shù)據(jù)的時(shí)候,就只剩下后面創(chuàng)建的數(shù)據(jù)了;
- 演示NSCache的代理方法
先設(shè)置代理對(duì)象:
- (void)viewDidLoad { [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//設(shè)置NSCache的代理
self.cache.delegate = self;
調(diào)用代理方法: 這里我僅用一個(gè)方法來演示:
//當(dāng)緩存被移除的時(shí)候執(zhí)行
- (void)cache:(NSCache *)cache willEvictObject:(id)obj{
NSLog(@"緩存移除 %@",obj);
}
輸出結(jié)果為:
通過結(jié)果可以看出:****NSCache的功能要比NSMutableDictionary的功能要強(qiáng)大很多很多;
4.當(dāng)遇到內(nèi)存警告的時(shí)候,
代碼演示:
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
//當(dāng)收到內(nèi)存警告顷级,清除內(nèi)存
[self.cache removeAllObjects];
//輸出緩存中的數(shù)據(jù)
for (int i = 0; i < 10; i++) {
NSLog(@"%@",[self.cache objectForKey:[NSString stringWithFormat:@"h%d",i]]);
}
}
控制臺(tái)輸出結(jié)果:
收到內(nèi)存警告
通過結(jié)果可以看出:當(dāng)收到內(nèi)存警告之后,清除數(shù)據(jù)之后,NSCache緩存池中所有的數(shù)據(jù)都會(huì)為空!
5.當(dāng)收到內(nèi)存警告,調(diào)用removeAllObjects 之后确垫,無(wú)法再次往緩存池中添加數(shù)據(jù)
代碼演示:
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
//當(dāng)收到內(nèi)存警告弓颈,調(diào)用removeAllObjects 之后,無(wú)法再次往緩存中添加數(shù)據(jù)
[self.cache removeAllObjects];
//輸出緩存中的數(shù)據(jù)
for (int i = 0; i < 10; i++) {
NSLog(@"%@",[self.cache objectForKey:[NSString stringWithFormat:@"h%d",i]]);
}
}
// 觸摸事件, 以便驗(yàn)證添加數(shù)據(jù)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.cache removeAllObjects];
//添加緩存數(shù)據(jù)
for (int i = 0; i < 10; i++) {
[self.cache setObject:[NSString stringWithFormat:@"hello %d",i] forKey:[NSString stringWithFormat:@"h%d",i]];
// NSLog(@"添加 %@",[NSString stringWithFormat:@"hello %d",i]);
}
//輸出緩存中的數(shù)據(jù)
for (int i = 0; i < 10; i++) {
NSLog(@"%@",[self.cache objectForKey:[NSString stringWithFormat:@"h%d",i]]);
}
}
控制臺(tái)輸出結(jié)果為:
輸出結(jié)果
通過輸出結(jié)果,我們可以看出:****當(dāng)收到內(nèi)存警告森爽,而我們又調(diào)用removeAllObjects 之后恨豁,則無(wú)法再次往緩存中添加數(shù)據(jù);