1. 定義
開啟官方文件,我們可以找到官方文件對於NSMapTable的定義:
The NSMapTable class is a mutable collection modeled after NSDictionary, with the following differences:
- The major option is to have keys and/or values held “weakly” in a manner that entries are removed when one of the objects is reclaimed.
- Its keys or values may be copied on input or may use pointer identity for equality and hashing.
- It can contain arbitrary pointers (its contents are not constrained to being objects).
You can configure an NSMapTable instance to operate on arbitrary pointers and not just objects, although typically you are encouraged to use the C function API for void * pointers. (See Managing Map Tables for more information) The object-based API (such as setObject:forKey:) will not work for non-object pointers without type-casting.
上面那段話大致的意思是,NSMapTable對於NSDictionary來說,有幾點特別的地方,其中表現在它可以指定key/value是需要strong,weak,甚至是copy,如果使用的是weak,當key、value在被釋放的時候,會自動從NSMapTable中移除這一項。NSMapTable中可以包含任意指標,使用指標去做檢查操作。
2. NSMapTable與NSDictionary
接下來我們針對上面提出的幾點優點,做一下淺析:
- NSDcitionary有一個可變的型別即NSMutableDictionary,然而NSMapTable沒有另外一個可變類,因為它本身就是可變的
- NSDcitionary或者NSMutableDictionary中對於key和value的記憶體管理是,對key進行copy,對value進行強引用。
- NSDcitionary中對於key的型別,我們看一下NSDitionary中的宣告:
1 |
+ (instancetype)dictionaryWithObject:(ObjectType)object forKey:(KeyType <NSCopying>)key; |
是需要key支援NSCopying協議,並且在NSDictionary中,object是由“key”來索引的,key的值不能改變,為了保證這個特性在NSDcitionary中對key的記憶體管理為copy,在複製的時候需要考慮對系統的負擔,因此key應該是輕量級的,所以通常我們都用字串和數字來做索引,但這隻能說是key-to-object對映,不能說是object-to-object的對映。
- NSMapTabTable更適合於我們一般所說的對映標準,它既可以處理key-to-value又可以處理object-to-object
3. 使用
接下來我們看一下NSMapTable的一般使用
1 2 3 4 |
- (instancetype)initWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER; - (instancetype)initWithKeyPointerFunctions:(NSPointerFunctions *)keyFunctions valuePointerFunctions:(NSPointerFunctions *)valueFunctions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER; + (NSMapTable<KeyType, ObjectType> *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions; |
我們會注意到在建立方法中有這麼一個選項keyOptions和valueOptions,值型別都是NSPointerFunctionsOptions,NSMapTable就是通過這個選項來設定key和value的記憶體管理型別,點選進去可以看到其中有這麼幾個選項:
1 2 3 4 5 6 |
static const NSPointerFunctionsOptions NSMapTableStrongMemory ; static const NSPointerFunctionsOptions NSMapTableZeroingWeakMemory; static const NSPointerFunctionsOptions NSMapTableCopyIn; static const NSPointerFunctionsOptions NSMapTableObjectPointerPersonality; static const NSPointerFunctionsOptions NSMapTableWeakMemory; |
根據參考資料中的描述
The options provided to NSMapTable are composed of three parts: a “memory option”, a “personality option” and the “copy in” flag. You may use one option for each part (there are default behaviors that will be used if no option is provided for the part). The parts are all bit flags (binary “or” them together to combine parts).Officially, NSMapTable allows the following options:
- NSMapTableStrongMemory (a “memory option”)
- NSMapTableWeakMemory (a “memory option”)
- NSMapTableObjectPointerPersonality (a “personality option”)
- NSMapTableCopyIn (a “copy option”)
- NSPointerFunctionsObjectPersonality
關於StrongMemory ,WeakMemory,TableCopyIn這三個都不難理解,對應的是key和value的記憶體管理型別,而關於Peronality這兩個選項是用來是用isEqual和hash比較標準
- NSMapTableStrongMemory: 類似於我們之前使用的NSSet
- NSPointerFunctionsWeakMemory: 用__weak來儲存
- NSPointerFunctionsCopyIn:對key和value進行copy處理
- NSPointerFunctionsObjectPersonality: isEqual和hash比較的是-description方法的值
- NSPointerFunctionsObjectPointerPersonality : isEqual和hash比較的是指標的地址
4. 例子
Rose 和 Jack的愛好
我們定義一個Person類,用來記錄人名,我們再建立一個Favourite類用來建立愛好物件,現在有Rose和Jack兩個人,分別的愛好是ObjC和Swift,人和愛好必須要用物件實現,而且必須關聯起來在一個表裡,以便我們進行查詢和記錄。如果是以前的話需要自己建立一個Dictionary,把人名的name欄位作為key,favourite的物件作為value。但是這樣有一個問題,如果突然某一天,我Person裡面增加了個欄位age,我這個表還要記錄每個人的年齡,供我以後來查詢不同年齡段的人統計使用呢?這下就很尷尬了,因為Dicitionary沒辦法實現我們要的這個效果,不過沒關係NSMapTable可以實現,我們來看程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Person *p1 = [[Person alloc] initWithName:@"jack"]; Favourite *f1 = [[Favourite alloc] initWithName:@"ObjC"]; Person *p2 = [[Person alloc] initWithName:@"rose"]; Favourite *f2 = [[Favourite alloc] initWithName:@"Swift"]; NSMapTable *MapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableWeakMemory]; // 設定對應關係表 // p1 => f1; // p2 => f2 [MapTable setObject:f1 forKey:p1]; [MapTable setObject:f2 forKey:p2]; NSLog(@"%@ %@", p1, [MapTable objectForKey:p1]); NSLog(@"%@ %@", p2, [MapTable objectForKey:p2]); |
我們來看一下列印出來的內容
1 2 |
2016-06-14 18:34:10.289 NSMapTableDemo[40414:1323838] jack favourite is ObjC 2016-06-14 18:34:10.290 NSMapTableDemo[40414:1323838] rose favourite is Swift |
我們建立了一個weak - weak的對映表,是不是不同類的物件一一對應起來了呢