NSPointerArray
特性介绍
NSPointerArray 是 NSArray 的通用版本,和 NSArray/NSMutableArray 不同的是,NSPointerArray 具有下面这些特性
- 与 NSArray/NSMutableArray 相对应,NSArray/NSMutableArray 强引用集合对象
- NSPointerArray 可以弱引用集合对象,一旦对象没人持有了,NSPointerArray 中对应的项会被变成
NULL
- NSPointerArray 是可变的,没有不可变的版本
- NSPointerArray 可以存储
NULL
,NULL
参与 count 计算 - NSPointerArray 的 count 可以被设置,如果直接设置 count,多余的位置会使用
NULL
占位 - NSPointerArray 存储的是指针类型
void *
而不是对象,所以需要__bridge
进行转换 - 使用 addPointer 和 pointerAtIndex 来存取指针
初始化参数
1 | - (instancetype)initWithOptions:(NSPointerFunctionsOptions)options; |
首先来看一下 NSPointerFunctionsOptions,它是个 option,主要分为三大类:
内存管理
- NSPointerFunctionsStrongMemory:默认值,强引用集合对象
- NSPointerFunctionsZeroingWeakMemory:废弃
- NSPointerFunctionsMallocMemory 与 NSPointerFunctionsMachVirtualMemory: 用于 Mach 的虚拟内存管理
- NSPointerFunctionsWeakMemory:弱引用集合对象
特性,用于标明对象判等方式
- NSPointerFunctionsObjectPersonality:hash、isEqual、对象描述
- NSPointerFunctionsOpaquePersonality:pointer 的 hash 、直接判等
- NSPointerFunctionsObjectPointerPersonality:pointer 的 hash、直接判等、对象描述
- NSPointerFunctionsCStringPersonality:string 的 hash、strcmp 函数、UTF-8 编码方式的描述
- NSPointerFunctionsStructPersonality:内存 hash、memcmp 函数
- NSPointerFunctionsIntegerPersonality:值的 hash
内存标识
- NSPointerFunctionsCopyIn:根据第二类的选择,来具体处理。如果是 NSPointerFunctionsObjectPersonality,则根据 NSCopying 来拷贝
这里只关注弱引用,对象判别方式和 NSPointerFunctions 的初始化不展开
提供 compact 方法剔除 NULL
元素
NSPointerArray 可以存储 NULL
,作为补充,它也提供了 compact 方法,用于剔除数组中为 NULL 的成员。但是 compact 函数有个已经报备的 bug,每次 compact 之前需要添加一个 NULL
,否则会 compact 失败
弱引用测试代码
1 | NSPointerArray *pointerArray = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsWeakMemory]; |
与 NSArray/NSMutableArray 的区别
NSArray/NSMutableArray 配合 NSValue 可以实现数组的弱引用
1 | NSMutableArray *array = @[].mutableCopy; |
注意:使用 NSValue 的方式,确实可以实现对对象的弱引用(即被添加到集合中时,对象的引用计数不会+1),但是当对象被释放的时候,数组中对应的对象会变成野指针,因此需要手动删除 NSArray 中对应对象的值,否则会在执行 [value nonretainedObjectValue]
时崩溃;而使用 NSPointerArray 不会有这个问题,对象的释放会使得集合中的对象变为 NULL
NSHashTable
特性介绍
NSHashTable 是 NSSet 的通用版本,和 NSSet / NSMutableSet 不同的是,NSHashTable 具有下面这些特性
- 与 NSSet/NSMutableSet 相对应,NSSet/NSMutableSet 强引用集合对象
- NSHashTable 可以弱引用集合对象,一旦对象没人持有了,NSHashTable 中的值也会被移除
- NSHashTable 是可变的,没有不可变的版本
- 除了存储对象,NSHashTable 也可以存储任意指针,比如
void *
初始化参数
可以在初始化 NSHashTable 时指定 NSHashTableOptions 来确定其内存引用
1 | + (NSHashTable<ObjectType> *)hashTableWithOptions:(NSPointerFunctionsOptions)options; |
NSHashTableOptions 的取值如下:
- NSHashTableStrongMemory: 默认值,强引用集合对象,与 NSSet 一样
- NSHashTableWeakMemory: 弱引用集合对象
- NSHashTableZeroingWeakMemory: 废弃,请使用 NSHashTableWeakMemory
- NSHashTableCopyIn: 在将对象添加到集合之前,会拷贝对象
- NSHashTableObjectPointerPersonality: 使用 shifted pointer 来做 hash 检测及确定两个对象是否相等
弱引用测试代码
1 | NSHashTable *hashTable = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; |
NSMapTable
特性介绍
NSMapTable 是 NSDictionary 的通用版本,和 NSDictionary/NSMutableDictionary 不同的是,NSMapTable 具有下面这些特性
- 与 NSDictionary/NSMutableDictionary 相对应,NSDictionary/NSMutableDictionary 对 Key 拷贝,对 Value 强引用
- key 和 value 的内存管理方式可以分开,如:key 是强引用,value 是弱引用
- NSMapTable 可以弱引用 Key 和 Value,一旦 Key 或 Value 中的某一个没人持有了,NSMapTable 中对应的项也会被移除
- NSMapTable 是可变的,没有不可变的版本
- 除了存储对象,NSMapTable 也可以存储任意指针,比如
void *
总结起来一共有 4 种可能:
- key 为 strong,value 为 strong
- key 为 strong,value 为 weak
- key 为 weak,value 为 strong
- key 为 weak,value 为 weak
当用 weak 修饰 key 或 value 时,有一方被释放,则该键值对移除。
初始化参数
可以在初始化 NSMapTable 时指定 NSPointerFunctionsOptions 来分别确定对 Key 和 Value 的内存引用
1 | + (NSMapTable<KeyType, ObjectType> *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions; |
- NSMapTableStrongMemory: 默认值,强引用 Key/Value
- NSMapTableWeakMemory: 弱引用 Key/Value
- NSHashTableZeroingWeakMemory: 废弃,请使用 NSMapTableWeakMemory
- NSMapTableCopyIn: 在将对象添加到集合之前,会拷贝对象
- NSMapTableObjectPointerPersonality: 使用 shifted pointer 来做 hash 检测及确定两个对象是否相等
弱引用测试代码
1 | NSMapTable *mapTable = [NSMapTable weakToStrongObjectsMapTable]; |
何时使用
NSHashTable 和 NSMapTable 都比 NSSet 和 NSDictionary 都更加强大,但是大部分情况下,我们用 NSSet 和 NSDictionary 就已经足够,只有在对内存有特别要求的情况下,才使用 NSHashTable 和 NSMapTable