什么是NSCache
NSCache是Foundation框架中的一个类,用于在iOS和macOS应用程序中进行临时性的内存缓存。它提供了一种轻量级的缓存机制,可以用于存储临时性的数据,例如图片、对象等。NSCache的主要特点和用法包括:
-
临时性缓存:NSCache用于存储需要临时性缓存的数据,这些数据在应用的生命周期内需要频繁访问,但并不需要永久保存。
-
自动管理内存:NSCache会自动管理缓存中的对象,当系统内存不足时,NSCache会自动释放部分缓存对象以腾出内存空间。
-
键值对存储:NSCache使用键值对的方式来存储和访问缓存数据。通过键(Key)可以快速查找对应的值(Value)。
-
线程安全:NSCache是线程安全的,多个线程可以同时读取和写入缓存,不需要额外的同步措施。
数据持久化的目的
- 快速展示,提升体验
- 已经加载过的数据,用户下次查看时,不需要再次从网络(磁盘)加载,直接展示给用户
- 节省用户流量(节省服务器资源)
- 对于较大的资源数据进行缓存,下次展示无需下载消耗流量
- 同时降低了服务器的访问次数,节约服务器资源。
- 离线使用。
- 用户浏览过的数据无需联网,可以再次查看。
- 部分功能使用解除对网络的依赖。(百度离线地图、图书阅读器)
- 无网络时,允许用户进行操作,等到下次联网时同步到服务端。
- 记录用户操作
- 草稿:对于用户需要花费较大成本进行的操作,对用户的每个步骤进行缓存,用户中断操作后,下次用户操作时直接继续上次的操作。
- 已读内容标记缓存,帮助用户识别哪些已读。
- 搜索记录缓存
…
数据持久化方式分类
在移动端的数据持久化方式总体可以分为以下两类:
- 内存缓存
对于使用频率比较高的数据,从网络或者磁盘加载数据到内存以后,使用后并不马上销毁,下次使用时直接从内存加载。
案例:
- iOS系统图片加载——[UIImage imageNamed:@“imageName”]
- 网络图片加载三方库:SDWebImage
- 磁盘缓存
将从网络加载的、用户操作产生的数据写入到磁盘,用户下次查看、继续操作时,直接从磁盘加载使用。
案例:
- 用户输入内容草稿缓存(如:评论、文本编辑)
- 网络图片加载三方库:SDWebImage
- 搜索历史缓存
NSCache缓存类的详解
NSCache在系统内存很低时,会自动释放一些对象。为了确保接收到内存警告时能够真正释放内存,最好调用一下removeAllObjects方法。
NScache的key只是做强引用,不需要实现NScopying协议。
NSCache的属性:
delegate代理属性
- totalCostLimit :缓存空间的最大成本,超出上限会自动回收对象。默认值是0没有限制。
- countLimit:能够缓存对象的最大数量,默认值也是0(默认没有限制)。
(当超出缓存最大成本或数量时,NSCache会把前面的数据即最开始存的给清除掉) - evictsObjectsWithDiscardedContent:标示是否回收废弃的内容,默认值是YES(自动回收)。
“成本” 指的是每个对象的缓存大小,通常以字节为单位。如果缓存中的对象总成本超过了这个限制,NSCache 会自动回收一些对象,直到总成本符合限制。默认值为 0,表示没有限制。
NSCache的方法:
-objectForKey:返回与键值关联的对象。通过指定键名调用该方法,可以获取到缓存中对应的对象。如果该键名没有对应的对象,则返回 nil。
-setObject: forKey: 在缓存中设置指定键名对应的值。通过指定键名和对象调用该方法,可以将对象存储到缓存中。与可变字典不同的是,缓存对象不会对键名进行复制操作,因此设置键值对的成本是 0 成本,不会消耗额外的内存。
在可变字典中,通常当你向字典中添加一个新的键值对时,字典会对键名进行复制操作,以确保字典中的键是唯一的。这种复制操作虽然可以保证字典中键名的唯一性,但也会在一定程度上消耗额外的内存。而在 NSCache 中,当你使用 -setObject:forKey: 方法设置键值对时,并不会对键名进行复制操作。这种设计使得在设置键值对时不会消耗额外的内存,这就是“0成本”的意思。
-setObject: forKey: cost: 在缓存中设置指定键名对应的值,并且指定该键值对的成本。成本cost用于计算记录在缓冲中所有对象的总成本。当出现内存警告,或者超出缓存的成本上限时,缓存会开启一个回收过程,删除部分元素。
-removeObjectForKey:删除缓存中指定键名的对象。通过指定键名调用该方法,可以从缓存中移除对应的对象。
-removeAllObjects:删除缓存中的所有对象。调用该方法会清空缓存中的所有对象,使缓存变为空缓存。
委托方法:
-cache: willEvictObject: 缓存将要删除对象时调用,不能在此方法中修改缓存。仅仅用于后台的打印,以便于程序员的测试。
示例:
#import "ViewController.h"@interface ViewController ()<NSCacheDelegate>@property (nonatomic, strong) NSCache *myCaChe;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];//设置缓存容器 self.myCaChe = [[NSCache alloc] init];self.myCaChe.countLimit = 10;self.myCaChe.totalCostLimit = 0;self.myCaChe.delegate = self;UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];btn.frame = CGRectMake(100, 300, 200, 80);[btn setTitle:@"按钮" forState:UIControlStateNormal];[self.view addSubview:btn];[btn addTarget:self action:@selector(touchPress) forControlEvents:UIControlEventTouchUpInside];
}static int a = 0;
- (void) touchPress{//将数据加入缓存 [self.myCaChe setObject:[NSString stringWithFormat:@"value - %d", a] forKey:@(a) cost:1000];NSLog(@"%@", [self.myCaChe objectForKey:@(a)]);a++;
}- (void)cache:(NSCache *)cache willEvictObject:(id)obj {//打印出被从缓存中删除的数据 NSLog(@"delete - %@", obj);
}@end