1,定义
NSMapTable对于NSDictionary来说,有几点特别的地方,其中表现在它可以指定key/value是需要strong,weak,甚至是copy,如果使用的是weak,当key、value在被释放的时候,会自动从NSMapTable中移除这一项。NSMapTable中可以包含任意指针,使用指针去做检查操作
2. NSMapTable与NSDictionary
《1》NSDcitionary有一个可变的类型即NSMutableDictionary,然而NSMapTable没有另外一个可变类,因为它本身就是可变的
《2》NSDcitionary或者NSMutableDictionary中对于key和value的内存管理是,对key进行copy,对value进行强引用。
《3》NSDcitionary中对于key的类型,我们看一下NSDitionary中的声明:
+ (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. 使用方法
- (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的内存管理类型,点击进去可以看到其中有这么几个选项:
static const NSPointerFunctionsOptions NSMapTableStrongMemory ;//类似于我们之前使用的NSSet
static const NSPointerFunctionsOptions NSMapTableWeakMemory;//用__weak来存储
static const NSPointerFunctionsOptions NSMapTableZeroingWeakMemory;//
static const NSPointerFunctionsOptions NSMapTableCopyIn;//对key和value进行copy处理
static const NSPointerFunctionsOptions NSMapTableObjectPersonality;//isEqual和hash比较的是-description方法的值
static const NSPointerFunctionsOptions NSMapTableObjectPointerPersonality;//isEqual和hash比较的是指针的地址
关于StrongMemory ,WeakMemory,TableCopyIn这三个都不难理解,对应的是key和value的内存管理类型,而关于Peronality这两个选项是用来是用isEqual和hash比较标准
4,举例
我们定义一个Person类,用来记录人名,我们再创建一个Favourite类用来创建爱好对象,现在有Rose和Jack两个人,分别的爱好是ObjC和Swift,人和爱好必须要用对象实现,而且必须关联起来在一个表里,以便我们进行查询和记录。如果是以前的话需要自己建立一个Dictionary,把人名的name字段作为key,favourite的对象作为value。但是这样有一个问题,如果突然某一天,我Person里面增加了个字段age,我这个表还要记录每个人的年龄,供我以后来查询不同年龄段的人统计使用呢?这下就很尴尬了,因为Dicitionary没办法实现我们要的这个效果,不过没关系NSMapTable可以实现,我们来看代码:
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]);
打印结果
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