NSCache
NSCache 并不会拷贝(copy)键,而是会保留(strong)键,NSdictionary 是会对键进行拷贝的。NSCahe对象不拷贝键是因为在很多时候键都是不支持拷贝的对象来充当的。因此NSCache对象不会自动拷贝键,所以在键不支持拷贝操作的情况下,该类比字典用起来更方便
当系统资源将要耗尽时,NSCache可以自动删减缓存。如果采用普通的字典,那么就要自己编写挂钩,在系统通知时手动删减缓存,NSCache会先行删减 时间最久为被使用的对象
NScache是线程安全的,NSDictionary不是。在开发者自己不编写加锁代码的前提下,多个线程可以同时访问NSCache。对缓存来说,线程安全通常是很重要的,因为开发者可能在某个线程中读取数据,此时如果发现缓存里找不着指定的键,那么就要下载该键对应的数据了
NSDictionary
NSDictionary 是我们比较常用的集合对象。
- NSDictionary 键(key)是被拷贝的并且需要是恒定的,通常我们用字符串类型对象作为键比较多,其他的对象也可以作为键,但是对象要遵守<NSCopying> 协议实现相应的copy方法即可。
- NSDictionary 对值(value)的是通过强引用来存储值对象的
- NSDictionary 不是线程安全的,多线程访问需要程序员自己编写保证线程安全的代码
- NSDictionary 所占内存不会想NSCache那样被系统自动清除,而是需要程序员自己处理内存使用问题
NSMapTable
- NSMapTable 相对NSDictionary来说对key和value具有更广泛的语义说明,可以指定key或value是拷贝、强引用或弱引用。
id delegate;//假设代理对象
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory];
[mapTable setObject:delegate forKey:@"foo"];
NSHashTable
NSHashTable是更广泛意义的NSSet,区别于NSSet / NSMutableSet,NSHashTable有如下特性:
- NSSet / NSMutableSet是对其成员的强类型引用,这些成员被通过hash方法和isEqual方法来完成哈希和对比功能
- NSHashTable是可变的
- NSHashTable可以持有weak类型的成员变量
- NSHashTable可以在添加成员变量的时候复制成员
- NSHashTable可以随意的存储指针并且利用指针的唯一性来进行hash同一性检查(检查成员变量是否有重复)和对比操作(equal),用法如下:
NSHashTable *hashTable = [NSHashTable hashTableWithOptions:NSPointerFunctionsCopyIn];
[hashTable addObject:@"foo"];
[hashTable addObject:@"bar"];
[hashTable addObject:@42];
[hashTable removeObject:@"bar"];
NSLog(@"Members: %@", [hashTable allObjects]);
NSSet
- NSSet 持有的对象都是强引用对象
- NSSet 集合内的对象是不重复的
User *u1 = [[User alloc] init];
User *u2 = [[User alloc] init];
NSSet *set = [NSSet setWithObjects:u1,u1,u2, nil]; //u1 retainCount = 2
打印输出:
(lldb) po set
{(
<User: 0x600001e34350>,
<User: 0x600001e341d0>
)}
NSArray
- NSArray 持有对象都是强引用对象
- NSArray集合内的对象是可以重复的,也就是同一个对象可以多次放入同一个数组中,放几次引用计数就会增加几次
User *u1 = [[User alloc] init]; //retainCount=1
NSArray *array = @[u1,u1,u2];// 添加2次retainCount = 3
printf("Retain Count = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(u1)));
打印结果:如下
Retain Count = 3
总结
这些集合对象各有优缺点我们在开发中要根据实际的业务需求去选择合适的集合对象处理数据,例如我们需要处理一些并不是在内存中需要一直存在的缓存数据,就可以用NSCache去处理,但如果是多线程访问的话NSCache 势必会带来一些性能上的损耗,因为它是线程安全的,这就要根据实际场景去做选择了。总之这些集合对象没有绝对的谁好谁差即合适的场景选择合适的结合对象。