NSCache
是蘋果提供的一個專門用來作緩存的類web
使用和 NSMutableDictionary
很是類似緩存
是線程安全的安全
當內存不足
的時候,會自動清理緩存網絡
程序開始時,能夠指定緩存的數量
& 成本
app
取值框架
- (id)objectForKey:(id)key;
測試
設置對象,0成本atom
- (void)setObject:(id)obj forKey:(id)key;
spa
設置對象並指定成本
線程
- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g;
成本示例,以圖片爲例:
方案一:緩存 100
張圖片
方案二:總緩存成本設定爲 10M
,以圖片的 寬 * 高
看成成本,圖像像素
。這樣,不管緩存的多少張照片,只要像素值超過 10M,就會自動清理
結論:在緩存圖像時,使用成本,比單純設置數量要科學!
刪除
- (void)removeObjectForKey:(id)key;
刪除所有(不要使用!)
- (void)removeAllObjects;
@property NSUInteger totalCostLimit;
緩存總成本
@property NSUInteger countLimit;
緩存總數量
@property BOOL evictsObjectsWithDiscardedContent;
是否自動清理緩存,默認是 YES
定義緩存屬性
@property (nonatomic, strong) NSCache *cache;
懶加載並設置限制
- (NSCache *)cache { if (_cache == nil) { _cache = [[NSCache alloc] init]; _cache.delegate = self; _cache.countLimit = 10; } return _cache; }
觸摸事件添加緩存
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (int i = 0; i < 20; ++i) { NSString *str = [NSString stringWithFormat:@"%d", i]; NSLog(@"set -> %@", str); [self.cache setObject:str forKey:@(i)]; NSLog(@"set -> %@ over", str); } // 遍歷緩存 NSLog(@"------"); for (int i = 0; i < 20; ++i) { NSLog(@"%@", [self.cache objectForKey:@(i)]); } }// 代理方法,僅供觀察使用,開發時不建議重寫此方法 - (void)cache:(NSCache *)cache willEvictObject:(id)obj { NSLog(@"remove -> %@", obj); }
修改圖像緩衝池類型,並移動到 .h
中,以便後續測試
/// 圖像緩衝池@property (nonatomic, strong) NSCache *imageCache;
修改懶加載,並設置數量限制
- (NSCache *)imageCache { if (_imageCache == nil) { _imageCache = [[NSCache alloc] init]; _imageCache.countLimit = 15; } return _imageCache; }
修改其餘幾處代碼,將 self.imageCache[URLString]
替換爲 [self.imageCache setObject:image forKey:URLString];
測試緩存中的圖片變化
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { for (AppInfo *app in self.appList) { NSLog(@"%@ %@", [[DownloadImageManager sharedManager].imageCache objectForKey:app.icon], app.name); } }
註冊通知,監聽內存警告
- (instancetype)init
{
self = [super init];
if (self) {
// 註冊通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearMemory) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
return self;
}
// 提示:雖然執行不到,可是寫了也無所謂 良好的代碼習慣
- (void)dealloc {
// 刪除通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
清理內存
- (void)clearMemory {
NSLog(@"%s", __FUNCTION__);
// 取消全部下載操做
[self.downloadQueue cancelAllOperations];
// 刪除緩衝池
[self.operationChache removeAllObjects];
}
注意:內存警告或者超出限制後,緩存中的任何對象,都有可能被清理。使用 NSCache 作緩存必定要保證可以有恢復的通道!
NSCache bug
#import "ViewController.h"
@interface ViewController ()<NSCacheDelegate>
@property(nonatomic,strong) NSCache *cache;
@end
@implementation ViewController
#pragma mark 懶加載
-(NSCache *)cache{
if(!_cache){
_cache = [[NSCache alloc] init];
//設置最大數量
_cache.countLimit = 10;
_cache.delegate = self;
}
return _cache;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self demo];
}
-(void)demo{
for (int i = 0; i < 20; i++) {
NSString *str = [NSString stringWithFormat:@"%d",i];
NSLog(@"add %@",str);
[self.cache setObject:str forKey:@(i)];
}
//輸出
for (int i = 0; i < 20; i++) {
NSLog(@"%@",[self.cache objectForKey:@(i)]);
}
}
- (void)didReceiveMemoryWarning {
//清空全部緩存,bug不靠譜,手動清空以後沒法再加入
[self.cache removeAllObjects];
[super didReceiveMemoryWarning];
}
#pragma mark delegate
-(void)cache:(NSCache *)cache willEvictObject:(id)obj{
//不推薦在這裏寫耗時操做
//模擬耗時操做
// [NSThread sleepForTimeInterval:1];
//將要驅逐對象
NSLog(@"evict %@",obj);
}
@end