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)];
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章