iOS开发-NSMapTable NSHashTable NSPointerArray的使用

对于工程中使用的弱引用集合的特性进行整理,有些点还是容易忘记

NSMapTable NSHashTable NSPointerArray 是iOS中用于存储弱引用对象方式,但不仅于此

  • NSMapTable 对应 NSMutableDictionary
  • NSHashTable 对应 NSMutableSet
  • NSPointerArray 对应 NSMutableArray

NSMapTable

NSDictionary的局限性

  1. Key必须为支持NSCopying协议的OC对象,NSDictonary会将设置的Key拷贝到自己的私有空间。

意味着你可以使用NSNumber或者NSString作为NSDictionary的Key

  1. Key必须小而高效,以保证拷贝复制的时候不会造成CPU和内存的负担。
  2. 会保持对Object的强引用,即Object的引用计数+1。

NSMapTable优势

  1. 能够处理obj->obj的映射

  2. 能够对Key和value保持弱引用,当key或者value被释放的时候,此entry对会自动从NSMapTable中移除。

  3. 能够以包含任意指针对象

配置参数 Options

NSMapTable 既可以处理NSDictionary key -> obj 式的映射,也可以处理 obj->obj 式的映射,根据不同的创建方式,我们可以构建不同的映射关系:

  • 像 NSDictionary 一样,复制 key,并对它的 object 引用计数 +1
NSMapTable *keyToObjectMapping =
    [NSMapTable mapTableWithKeyOptions:NSMapTableCopyIn    //对key拷贝
                          valueOptions:NSMapTableStrongMemory]; //强引用object
  • 真正的对象到对象(object-to-object)的映射
NSMapTable *objectToObjectMapping = [NSMapTable mapTableWithStrongToStrongObjects];

NSMapTable 的配置都来自枚举 NSPointerFunctionsOptions ,其中 NSMapTable 可以使用的值如下

  • Memory Option
  1. NSMapTableStrongMemory = NSPointerFunctionsStrongMemory 指定相应的key或者value为强引用

  2. NSMapTableWeakMemory = NSPointerFunctionsWeakMemory 指定相应的key或者value为弱引用

当不指定时,NSMapTableStrongMemory 是默认的 “memory option”

  • Personality Option

用于对比时采用的规则,例如是比较指针,还是比较Int值,还是cstring

  1. NSMapTableObjectPointerPersonality = NSPointerFunctionsObjectPointerPersonality 此选项是直接使用指针进行isEqual:和hash
  • Copy Option
  1. NSMapTableCopyIn = NSPointerFunctionsCopyIn 指定相应的key或者value在增加到集合中的时候为copy

你可以在 NSMapTable.h 查看

Memory Option

ARC下

当设置为 NSMapTableWeakMemory 时,key或者value被释放的时候,此entry对会自动从NSMapTable中移除。

    NSMapTable *map = [[NSMapTable alloc] initWithKeyOptions:NSMapTableObjectPointerPersonality|NSMapTableWeakMemory
    valueOptions:NSMapTableWeakMemory
        capacity:20];
    
    @autoreleasepool {
        NSObject *key = [NSObject new];
        NSLog(@"map key : %@",key);
        NSObject *value = [NSObject new];
        NSLog(@"map value : %@",value);
        [map setObject:value forKey:key];
    }
    
    NSLog(@"map enties : %@",map);

日志输出为:

2020-06-18 14:20:28.206834+0800 GIOTest[54945:4954293] map key : <NSObject: 0x6000023943a0>
2020-06-18 14:20:28.206954+0800 GIOTest[54945:4954293] map value : <NSObject: 0x600002398750>
2020-06-18 14:20:28.207069+0800 GIOTest[54945:4954293] map enties : NSMapTable {
}

MRC下

  1. 当设置为 NSMapTableWeakMemory 时,不会调用 retain 和 release
  2. 当设置为 NSMapTableStrongMemory 时,会调用 retain 和 release

同时需要保证 Personality options 的配置满足是 Objective-C objects 类型。

Personality options

NSMapTableObjectPointerPersonality 用指针来代替实际的值,当对象加入集合中时,会调用其isEqualTo:hash方法呢?,还是会直接对指针Pointer直接位移进行计算散列值,并直接判断指针是否相等

  • 如果option中设置 NSMapTableObjectPointerPersonality,那么会直接对指针Pointer直接位移进行计算散列值,并直接判断指针是否相等
  • 如果option中没有设置 NSMapTableObjectPointerPersonality (默认情况),那么会调用对象的isEqualTo:hash方法,来判断是否相等。

当打印这个指针的时候相当于调用description方法,我们重写description方法,打印如下:

2020-06-18 14:35:32.347062+0800 GIOTest[55031:4964477] map key : my description 0x6000038f0330
2020-06-18 14:35:32.347166+0800 GIOTest[55031:4964477] map value : my description 0x6000038e41a0
2020-06-18 14:35:32.347300+0800 GIOTest[55031:4964477] map enties : NSMapTable {
[18] my description 0x6000038f0330 -> my description 0x6000038e41a0
}

Usage

快捷生成

可以使用自带类方法生成各个类型的NSMapTable

// strong -> strong
+ (NSMapTable<KeyType, ObjectType> *)strongToStrongObjectsMapTable API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0));
// weak -> strong
+ (NSMapTable<KeyType, ObjectType> *)weakToStrongObjectsMapTable API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0)); // entries are not necessarily purged right away when the weak key is reclaimed
// strong -> weak
+ (NSMapTable<KeyType, ObjectType> *)strongToWeakObjectsMapTable API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0));
// weak -> weak
+ (NSMapTable<KeyType, ObjectType> *)weakToWeakObjectsMapTable API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0)); // entries are not necessarily purged right away when the weak key or object is reclaimed

自定义配置

  • Key为强引用,并对指针进行hash计算判断是否相等,Value保持弱引用
[[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
                                                            | NSPointerFunctionsObjectPersonality
                                              valueOptions:NSPointerFunctionsWeakMemory
                                                  capacity:2];
  • Key为强引用,并对指针进行hash计算判断是否相等,Value保持强引用
[[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory|NSPointerFunctionsObjectPointerPersonality
                                                    valueOptions:NSPointerFunctionsStrongMemory
                                                        capacity:3];

NSHashTable

在理解 NSMapTable 的基础上,理解 NSHashTable

NSHashTable 优势

  1. 可以持有weak类型的成员变量
  2. 可以随意的存储指针并且利用指针的唯一性来进行hash同一性检查

配置参数

  • NSHashTableStrongMemory = NSPointerFunctionsStrongMemory 对成员变量进行强引用。这是一个默认值。如果采用这个默认值,NSHashTableNSSet 就没什么区别了。
  • NSHashTableWeakMemory = NSPointerFunctionsWeakMemory 对成员变量进行弱引用
  • NSHashTableCopyIn = NSPointerFunctionsCopyIn 加入到集合中之前复制
  • NSHashTableObjectPointerPersonality = NSPointerFunctionsObjectPointerPersonality 用指针来等同代替实际的值,当打印这个指针的时候相当于调用description方法

Usage

使用 NSHashTable 一般都是使用其弱引用关系

  1. 创建弱引用关系,并存储指针
[[NSHashTable alloc] initWithOptions:NSHashTableWeakMemory |
    NSPointerFunctionsObjectPointerPersonality
                               capacity:100];
  1. 类方法创建
[NSHashTable weakObjectsHashTable]

NSPointerArray

NSPointerArray 特性

  1. 与NSMutableArray一样,使用下标有序的插入或移除元素,且可修改数组内容
  2. 可以插入或删除nil,并且 nil 参与 count 的计算
  3. count 可以 set,如果直接 set count,那么会使用 nil 占位
  4. 可以使用 weak 来修饰成员
  5. 成员可以是所有指针类型
  6. 遵循 NSFastEnumeration,可以通过 for…in 来进行遍历
  7. 当options配置 Personality options 为对象使用时,NSCopying 和 NSSecureCoding 协议才适用
  8. 当options配置为 NSPointerFunctionsWeakMemory ,对象释放的时候,并不会从数组中删除,count不会改变

创建

// 根据指定选项返回新指针数组 - 强引用
NSPointerArray *pointerArray = [[NSPointerArray alloc]initWithOptions:NSPointerFunctionsStrongMemory];

// 根据指定函数返回新指针数组 - 弱引用
NSPointerFunctions *functions = [[NSPointerFunctions alloc]initWithOptions:NSPointerFunctionsWeakMemory];
NSPointerArray *pointerArray1 = [[NSPointerArray alloc]initWithPointerFunctions:functions];


// 返回一个强引用元素的数组
NSPointerArray *pointerArray2 = [NSPointerArray strongObjectsPointerArray];

// 返回一个弱引用元素的数组
NSPointerArray *pointerArray3 = [NSPointerArray weakObjectsPointerArray];

Usage

// 设置数组元素数量
pointerArray.count = 5;

// 数组中元素数量
NSUInteger count = [pointerArray count];//5  @[nil,nil,nil,nil,nil] 

// 指定索引处的指针
void *point = [pointerArray pointerAtIndex:0];//nil 

// 数组中添加指针对象
[pointerArray addPointer:@"2"];//实际打印输出(2)  内部存储结构为 @[nil,nil,nil,nil,nil,@"2"] 

// 移除指定索引处的元素
[pointerArray removePointerAtIndex:0];//实际打印输出() 内部存储结构为@[nil,nil,nil,nil,@"2"] 

// 指定索引出插入元素
[pointerArray insertPointer:@"1" atIndex:0];//实际打印输出(1,2)  内部存储结构为@[@"1",nil,nil,nil,nil,@"2"] 

// 替换指定索引处的对象
[pointerArray replacePointerAtIndex:0 withPointer:@"2"];//实际打印输出(2,2) 内部存储结构@[@"2",nil,nil,nil,nil,@"2"]

// 删除数组中的nil值
[pointerArray addPointer:NULL];//仅compact无法清除nil,需要在之前addPointer:NULL
[pointerArray compact]; //此时count=1

//添加自定义对象
CCObject *key = [CCObject new];
[pointerArray addPointer:(__bridge void * _Nullable)(key)];
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章