1.NSCache
通常使用NSCache对象临时存储具有创建成本高昂的瞬时数据的对象。重用这些对象可以提高性能,因为它们的值不必重新计算。然而,这些对象对应用程序来说并不重要,如果内存不足,可以将其丢弃。如果丢弃,则在需要时必须重新计算它们的值。
NSCache是一个可变键值对集合,使用方式和NSMutableDictionary基本是相同。不过相对于NSMutableDictionary,NSCache有以下几个区别:
1.NSCache是线程安全的,NSMutableDictionary线程不安全。
2.当内存不足时,NSCache可能会自动删除键值对以释放内存,所以从缓存中取数据的时候总要判断是否为空。删除策略未知。
3.NSCache可以指定缓存限额,当缓存超出限额时自动释放内存。
4.NSCache的键只是对对象的强引用,对象不需要实现NSCopying协议。NSMutableDictionary的键会copy对象,对象必须实现NSCopying协议。
// UIView对象没有实现NSCopying协议
UIView *view = [[UIView alloc] init];
// 没有问题
[self.cache setObject:view forKey:view];
// 会崩溃,因为key没有实现NSCopying协议
[self.dic setObject:view forKey:view];

使用方式
1.设置缓存限额
// 缓存数量
@property NSUInteger countLimit;
// 缓存成本
@property NSUInteger totalCostLimit;
2.监听元素移除
@property (nullable, assign) id<NSCacheDelegate> delegate;
// 在移除元素之前,会回调下面的方法,返回要移除的元素。
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
代码演示:
#import "ViewController.h"
@interface ViewController () <NSCacheDelegate>
// 定义缓存池
@property (nonatomic, strong) NSCache *cache;
@end
@implementation ViewController
- (NSCache *)cache {
if (_cache == nil) {
_cache = [[NSCache alloc] init];
// 缓存中总共可以存储多少条
_cache.countLimit = 5;
// 缓存的数据总量为多少,5k
_cache.totalCostLimit = 1024 * 5;
// 设置代理
_cache.delegate = self;
}
return _cache;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 添加缓存数据
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]);
}
// 输出缓存中的数据
for (int i = 0; i < 10; i++) {
NSLog(@"%@",[self.cache objectForKey:[NSString stringWithFormat:@"h%d",i]]);
}
}
// 当缓存被移除的时候执行
- (void)cache:(NSCache *)cache willEvictObject:(id)obj{
NSLog(@"缓存移除 %@",obj);
}
控制台输出结果为:

2.NSMapTable
NSMapTable是一个可变键值对集合,使用方式和NSMutableDictionary基本是相同。不过相对于NSMutableDictionary,NSMapTable有以下几个区别:
1.可以设置是否强引用键对象,NSMutableDictionary只能强引用键对象。如果键对象释放了,NSMapTable会自动移除键值对。
2.可以设置是否强引用值对象,NSMutableDictionary只能强引用值对象。如果值对象释放了,NSMapTable会自动移除键值对。
、、、
// 键值都是强引用,相当于NSMutableDictionary
- (NSMapTable<KeyType, ObjectType> *)strongToStrongObjectsMapTable; // 键对象是弱引用,值对象是强引用。当键对象释放的时候,NSMapTable就会移除这对键值对。
- (NSMapTable<KeyType, ObjectType> *)weakToStrongObjectsMapTable; // 键对象是强引用,值对象是弱引用。当值对象释放的时候,NSMapTable就会移除这对键值对。
- (NSMapTable<KeyType, ObjectType> *)strongToWeakObjectsMapTable;
- // 键值都是弱引用。当键对象或者值对象只要有一个释放,NSMapTable就会移除这对键值对。
- (NSMapTable<KeyType, ObjectType> *)weakToWeakObjectsMapTable; 、、、
代码演示
- (void)viewDidLoad {
NSMutableString *key = [[NSMutableString alloc] initWithString:@"key"];
NSMutableString *value = [[NSMutableString alloc] initWithString:@"value"];
NSMapTable *mapTable = [NSMapTable weakToStrongObjectsMapTable];
[mapTable setObject:value forKey:key];
NSLog(@"释放之前---%@", mapTable);
key = nil;
NSLog(@"释放之后---%@", mapTable);
}
控制台输出结果为:
释放之前---NSMapTable {
[5] key -> value
}
释放之后---NSMapTable {
}
3.NSHashTable
NSHashTable是一个可变集合,使用方式和NSMutableSet基本是相同。不过相对于NSMutableArray,NSMutableArray有以下几个区别:
1.可以设置集合内元素的内存管理方式,例如强引用,弱引用。当元素弱引用并释放的时候,NSHashTable会自动移除这个元素。
代码演示
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *object = [[NSMutableString alloc] initWithString:@"object"];
// 设置对集合内的元素为弱引用
NSHashTable *hashTable = [NSHashTable weakObjectsHashTable];
[hashTable addObject:object];
NSLog(@"释放之前---%@", hashTable);
object = nil;
NSLog(@"释放之后---%@", hashTable);
}
控制台输出结果为:
释放之前---NSHashTable {
[1] object
}
释放之后---NSHashTable {
}