简介
开发中经常使用的集合类型有 NSArray、NSDictionary、NSSet,这三种集合类型可以解决大部分需求场景,但如果涉及到弱引用集合类、NSCopying 相关问题,则对应可以使用 NSPointerArray、NSMapTable、NSHashTable。
对应关系
NSPointerArray 对应 NSArray、NSMutableArray
NSMapTable 对应 NSDictionary、NSMutableDictionary
NSHashTable 对应 NSSet、NSMutableSet
特点
1.NSPointerArray、NSMapTable、NSHashTable 三者都是可变类型,没有不可变的父类
2.在添加元素时,无须判空,可以直接添加 NULL、nil 等空值,见下方示例代码:
示例代码:
1
2
3
4
5
6
7
8
9
10
11
|
NSPointerArray *pointerArray = [[NSPointerArray alloc] init];
[pointerArray addPointer:nil];
[pointerArray addPointer:NULL];
NSMapTable *mapTable = [[NSMapTable alloc] init];
[mapTable setObject:NULL forKey:NULL];
NSHashTable *hashTable = [[NSHashTable alloc] init];
[hashTable addObject:NULL];
NSLog(@"\n\npointerArray = %@count = %ld\n\nmapTable = %@count = %ld\n\nhashTable = %@count = %ld", pointerArray,pointerArray.count, mapTable,mapTable.count, hashTable, hashTable.count);
|
打印:
1
2
3
4
5
6
7
8
9
|
pointerArray = <NSConcretePointerArray: 0x600001d50460>count = 2
mapTable = NSMapTable {
}
count = 0
hashTable = NSHashTable {
}
count = 0
|
3.三者都拥有初始化方法 - (instancetype)initWithOptions:(NSPointerFunctionsOptions)options
,参数 options 代表其所支持的放入对象的指针管理选项:
1
2
3
|
NSPointerArray *pointerArray = [[NSPointerArray alloc] initWithOptions:<#(NSPointerFunctionsOptions)#>];
NSMapTable *mapTable = [[NSMapTable alloc] initWithKeyOptions:<#(NSPointerFunctionsOptions)#> valueOptions:<#(NSPointerFunctionsOptions)#> capacity:<#(NSUInteger)#>];
NSHashTable *hashTable = [[NSHashTable alloc] initWithOptions:<#(NSPointerFunctionsOptions)#> capacity:<#(NSUInteger)#>];
|
options 值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
typedef NS_OPTIONS(NSUInteger, NSPointerFunctionsOptions) {
// 每种类别的选项互斥,只能每种类别选择一个
// Memory Options(内存语义管理选项)
NSPointerFunctionsStrongMemory, // 和 strong 一样,默认
NSPointerFunctionsZeroingWeakMemory, // 已废弃,在 GC 下,弱引用指针,防止悬挂指针
NSPointerFunctionsOpaqueMemory, // 在指针去除时不做任何动作
NSPointerFunctionsMallocMemory, // 去除时调用 free() , 加入时 calloc()
NSPointerFunctionsMachVirtualMemory, // 使用可执行文件的虚拟内存
NSPointerFunctionsWeakMemory, // 和 weak 一样
// Personaility Options(对象处理选项-如何进行哈希算法,判定等同性,描述)
NSPointerFunctionsObjectPersonality, // 使用 NSObject 的 hash、isEqual、description,默认
NSPointerFunctionsOpaquePersonality, // 使用偏移后指针,进行 hash 和直接比较等同性
NSPointerFunctionsObjectPointerPersonality, // 和上一个相同,多了 description 方法
NSPointerFunctionsCStringPersonality, // 使用 c 字符串的 hash 和 strcmp 比较,%s 作为 decription
NSPointerFunctionsStructPersonality, // 使用内存的 hash 和 memcmp
NSPointerFunctionsIntegerPersonality, // 使用偏移量作为 hash 和等同性判断
// Copy Options(对象拷贝选项)
NSPointerFunctionsCopyIn, // 通过 NSCopying 方法,复制后存入
};
|
由上述可知,当我们选择 NSPointerFunctionsWeakMemory
时,属于弱引用。
4.NSMapTable 的 key 无须遵守 NSCopying 协议
我们在使用 NSDcitionary 时,可以看到 key 的类型遵守了 NSCopying 协议,因为 value 是根据 key 值来查找的,因此 key 值不可改变,为了保证这个特性所以使用了 NSCopying 协议。总结来说,NSDcitionary 的映射关系是 object : string
,而 NSMapTabTable 的映射关系是 object : object
。
1
|
NSDictionary dictionaryWithObject:<#(nonnull ObjectType)#> forKey:<#(nonnull id<NSCopying>)#>
|
可以看个例子:
1
2
3
4
5
6
7
8
|
NSObject *a1 = [[NSObject alloc] init];
NSObject *a2 = [[NSObject alloc] init];
NSObject *b1 = [[NSObject alloc] init];
NSObject *b2 = [[NSObject alloc] init];
NSDictionary *dict = @{a1:b1,a2:b2};
NSLog(@"%@", dict);
|
上述代码会报错:-[NSObject copyWithZone:]: unrecognized selector sent to instance 0x600000998180
,因为它的 key 是
NSObject 类型,没有遵守 NSCopying 协议;
而我们使用 NSMapTabTable 来处理这种场景时,就不会有什么问题:
1
2
3
4
5
6
7
8
9
10
|
NSObject *a1 = [[NSObject alloc] init];
NSObject *a2 = [[NSObject alloc] init];
NSObject *b1 = [[NSObject alloc] init];
NSObject *b2 = [[NSObject alloc] init];
NSMapTable *table = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsWeakMemory capacity:2];
[table setObject:b1 forKey:a1];
[table setObject:b2 forKey:a2];
NSLog(@"table:%@", table);
|
打印结果:
1
2
3
4
|
table:NSMapTable {
[10] <NSObject: 0x600001fe4180> -> <NSObject: 0x600001fe41f0>
[11] <NSObject: 0x600001fe4200> -> <NSObject: 0x600001fe41e0>
}
|
5.NSPointerArray、NSMapTable、NSHashTable 在 add..
时性能欠佳
具体可以参考 NSArray, NSSet, NSOrderedSet, and NSDictionary。
6.API 提供相对较少
这个可以直接到相关 API 中去查看,比如 NSPointerArray 并没有提供 sort、contain 等 API。
总结
基于 NSPointerArray、NSMapTable、NSHashTable 三者的特点,可以做一些 NSArray、NSDictionary、NSSet 无法做到的事情,比如弱引用、或者存储键值对 key 值非 string 类型的对象等等,但鉴于三者在 add 元素时性能较差,以及相对可用的 API 也相对较少,还是要谨慎使用。我目前了解到的是一般第三方库会使用的较多,比如 SDWebImage、IGListKit、YYText 等等,当然项目里也会使用,但使用相对较少,主要还是使用 NSArray、NSDictionary、NSSet 这些。
参考文献: