0x01 场景分析
需要创建一个集合,但是又不想让集合引用内部变量,这样就可以在内部变量被销毁是,不会因为集合引用了这个变量而导致无法被销毁。
如果我们使用NSMutableSet
来进行操作,就会因为NSMutableSet
对内部的元素多一个强引用导致无法释放。那么有没有其他集合方案可以让我们自由控制内存引用关系呢。
在iOS6.0
是就已经提供了支持,目的是为了拓展集合对内部元素的引用关系。
NSHashTable
相当于NSMutableSet
,但是可以对其内部的引用关系做额外设置,不像NSMutableSet
只是用来做强引用。
0x02 NSHashTable
NSHashTable
允许我们自定义集合对其内部元素的内存引用方案。更广泛意义的NSSet
,区别于NSSet
/NSMUtableSet
, NSHashTable
有以下特性
- 可变
- 可以持有
weak
类型的成员变量 - 可以再添加成员变量的时候复制成员
- 可以任意的存储指针,并且利用指针的唯一性来进行对比和重复检查。
可行的方案
// 对成员变量进行强引用
NSHashTableStrongMemory / NSPointerFunctionsStrongMemory
// 在ARC下使用弱引用方式进行读写,在最后一次释放后,引用对象将会被置为NULL
NSHashTableWeakMemory / NSPointerFunctionsWeakMemory
// 在对象被加入到集合中前进行复制
NSHashTableCopyIn / NSPointerFunctionsCopyIn
// 用指针来等同替代实际的值,当打印这个指针时,相当于调用了description方法
NSHashTableObjectPointerPersonality / NSPointerFunctionsObjectPointerPersonality
// 存储时,对要存储的对象A进行弱引用,当A被释放时,会自动在table中移除
NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
// NSHashTable *table = [NSHashTable weakObjectsHashTable]; 功能一样
Aobj *a = [Aobj new];
[table.addObject:a];
// 强引用,与NSMUtableSet功能一样
NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory];
Aobj *a = [Aobj new];
[table.addObject:a];
0x03 NSMapTable
NSMapTable
是更广泛意义的NSMutableDictionary
,我们可以自定义内存管理方案。
NSDictionary
/NSMutableDictionary
会赋值keys
并且通过强引用value
来实现存储。
NSMapTable
和NSDictionary
/NSMUtableDictionary
相比具有以下特性:
- 可变
- 可以通过弱引用来持有
keys
和values
,所以当key
或者value
被deallocated
的时候,所存储的实体也会被移除。 - 可以在添加
value
的时候对value
进行复制 - 可以任意的存储指针 ,并且利用指针的唯一性来进行对比和重复性检测。
可行性方案:
// 对成员变量进行强引用
NSMapTableStrongMemory / NSPointerFunctionsStrongMemory
// 对成员变量进行弱引用
NSMapTableWeakMemory
// 在对象被加入到字典中前进行复制
NSMapTableCopyIn / NSPointerFunctionsCopyIn.
// 用指针来等同替代实际的值
NSMapTableObjectPointerPersonality / NSPointerFunctionsObjectPointerPersonality
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableCopyIn valueOptions:NSMapTableCopyIn]; // value使用copyIn,Person需要实现NSCopying协议
{
Person *p = [Person new];
[mapTable setObject:p forKey:@"foo"];
}
NSLog(@"Keys: %@", [[mapTable keyEnumerator] allObjects]);
NSLog(@"values:%@",[mapTable objectForKey:@"foo"]);
注意:NSMapTable
不能继承subscripting
因为下标访问需要一个id
作为key
,对于NSMapTable
来说,这不是强制的。
0x04 NSPointArray
一个稀疏数组,与NSMutableArray
相似,但可以存储NULL
值。如果存在NULL
索引会发生改变。
在性能方面,NSPointerArray
非常慢,所以当你打算在一个很大的数据集合上使用它时一定要三思。
可行性方案:
// 对成员变量进行强引用
NSPointerFunctionsStrongMemory
// 对成员变量进行弱引用
NSPointerFunctionsWeakMemory
// 在加入集合前执行copy
NSPointerFunctionsCopyIn
// 使用对象的hash和isEqual:(默认)。
NSPointerFunctionsObjectPersonality
// 对于isEqual:和hash使用直接的指针比较。
NSPointerFunctionsObjectPointerPersonality
NSPointerArray *ptrArray = [NSPointerArray pointerArrayWithOptions:NSPointerFunctionsWeakMemory];
// NSPointerArray *ptrArray = [NSPointerArray weakObjectsPointerArray]; 效果一样
for (int i = 0; i < 3; i ++)
{
Person *p = [Person new];
[ptrArray addPointer:(__bridge void *)p];
}
void *a = (__bridge void *)@10;
// void *a = 10; 会crash,原因就是在
[ptrArray addPointer:a];
NSLog(@"---%@",ptrArray.allObjects);
0x05 NSPointerFunctionsOptions
是一个option
,主要分为三大类:
内存管理语义
// 缺省值,在 CG 和 MRC 下强引用成员
NSPointerFunctionsStrongMemory
// 在指针去除时不做任何动作
NSPointerFunctionsOpaqueMemory
// 用于 Mach 的虚拟内存管理
NSPointerFunctionsMallocMemory 与 NSPointerFunctionsMachVirtualMemory
// 在 CG 或者 ARC 下,弱引用成员
NSPointerFunctionsWeakMemory
特性
对象处理选项即如何进行哈希算法,判定同等性,描述
// 使用NSObject的hash, isEqual, description,默认
NSPointerFunctionsObjectPersonality
//使用偏移后指针,进行hash和直接比较同等性
NSPointerFunctionsOpaquePersonality
// 和上一个相同,多了description方法
NSPointerFunctionsObjectPointerPersonality
// 使用C字符串的hash、strcmp 函数、UTF-8 编码方式的描述
NSPointerFunctionsCStringPersonality
// 使用内存的hash、memcmp
NSPointerFunctionsStructPersonality
// 使用偏移量作为hash和等同性判断
NSPointerFunctionsIntegerPersonality
内存标识
// 根据第二类的选择,来具体处理
// 如果是 NSPointerFunctionsObjectPersonality,则根据 NSCopying 来拷贝。
NSPointerFunctionsCopyIn
注意: 每种类别的选项只能选择一个
所以在使用时,可以多个组合。比如:需要强引用成员,使用对象方式对比,并且add
时copy
对象
NSPointerFunctionsOptions *options = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality | NSPointerFunctionsCopyIn;
0x06 总结
正常情况下我们使用NSArray
/NSMutableArray
,NSSet
/NSMutableSet
, NSDictionary
/NSMutableDictionary
就可以达到90%
以上的需求。如果自定义程度更高,我们就可以去考虑使用NSHashTable
,NSMapTable
,NSPointerArray
来解决问题。
参考:
https://blog.csdn.net/u012597860/article/details/51240430
https://www.cnblogs.com/zhaoguowen/p/4273237.html
https://www.cnblogs.com/lxlx1798/p/6651949.html
网友评论