您的位置:首页 > 移动开发 > IOS开发

iOS NSMapTable

2016-07-24 22:17 561 查看
http://www.isaced.com/post-235.html


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中的声明:

Objective-C

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的一般使用Objective-C

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的内存管理类型,点击进去可以看到其中有这么几个选项:

Objective-C

123456static 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可以实现,我们来看代码:Objective-C

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]);

我们来看一下打印出来的内容

Objective-C

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的映射表,是不是不同类的对象一一对应起来了呢


参考资料

NSMapTable: more than an NSDictionary for weak
pointers


NSMapTable: 不只是一个能放weak指针的 NSDictionary

NSMapTable是早在Mac OS X 10.5(Leopard)的引入集合类。乍一看,这似乎是作为一个替换NSDictionary的存在,可以选择“strong”和“week”指针。在这篇文章中,我会告诉你除了为什么它也非常有用之外的还有垃圾回收机制以及它是如何做NSDictionary中不能(或不应该)做的事情。

Leopard 中更多的Cocoa API

可可增加了几个新的集合类在Mac OS X 10.5(Leopard)的。这些措施包括:
NSPointerArray
NSHashTable
NSMapTable
NSPointerArray完全是新的,但大部分的 
NSHashTable
 和 
NSMapTable
 的功能之前可从opaque
Foundation C structs of the same names 看到。
在某些方面,这些新的类,像
NSMutableArray
, 
NSMutableSet
和的
NSMutableDictionary
一样工作,但是给了你使用“week”垃圾回收指针的选择。如果您使用的
Objective-C 2.0 垃圾回收机制,你应该知道什么是使用“week”指针,因此使用此选项的优势应该是清楚的。
NSPointerArray也可用于纯指针(指针不一定是Objective-C的类),但
NSHashTable
和的
NSMutableArray
类都需要它们的内容是Objective-C的对象。
虽然在一般意义上,NSPointerArray and NSHashTable 被设计为可以替换 NSMutableArray and NSMutableSet 的角色(有序和无序阵列)。

NSMapTable则是不同的,因为它可以在你的设计中使用,而NSMutableDictionary不能(或不应该)。

NSDictionary的局限性

NSDictionary提供了key-to-object的映射。从本质上讲,NSDictionary中存储的object位置是由“key”来索引的。
由于对象存储在特定位置,NSDictionary中要求key的值不能改变(否则object的位置会突然错误)。为了保证这一点,NSDictionary中始终复制key到它私有位置。
这个key的复制行为也是NSDictionary如何工作的基础,但这也有一个限制:你可以只使用Objective-C对象作为NSDictionary的key,如果它支持NSCopying协议。此外,key应该是小且高效的,以至于复制的时候不会对CPU和内存造成负担。
这意味着,NSDictionary中真的只有适合“value”类型的对象作为key(如简短字符串和数字)。这不是离线的对象到对象的映射模型。

对象到对象的映射

NSMapTable(顾名思义)更适合于一般意义的映射。这取决于它是如何构造的,NSMapTable可以处理的“key-to-object”样式映射的NSDictionary,但它也可以处理“object-to-object”的映射 - 也被称为“associative
array”或简称为“map”。
例如,一个NSMapTable构造如下:
NSMapTable *keyToObjectMapping =
[NSMapTable
mapTableWithKeyOptions:NSMapTableCopyIn
valueOptions:NSMapTableStrongMemory];

将会和NSMutableDictionary工作得一样一样的,复制其“key”,并retaining它的“object”。
一个纯粹的对象到对象(object-to-object)的映射可以构造如下:
NSMapTable *objectToObjectMapping =
[NSMapTable mapTableWithStrongToStrongObjects];

一个对象到对象(object-to-object)的行为可能以前可以用NSDictionary来模拟,如果所有的key都是一个NSNumber包含于该映射的源对象的内存地址(不要笑,我见过这种情况),但这些内存地址都是奔波在外,Cocoa中首次提供了一个真正的对象到对象的映射NSMapTable。

NSMapTable的选项

NSMapTable提供的选项是由三部分组成:一个“memory option”(内存选项),一个“personality option”和“copy in”标志。你可以为每个部分使用一个选项(如果没有提供一个选项的部分将会使用默认行为),这个部分都是位标志(bit flag)(二进制 “or” 合并在一起)。
理论上,NSMapTable允许以下选项:
NSMapTableStrongMemory (a "memory option")
NSMapTableWeakMemory (a "memory option")
NSMapTableObjectPointerPersonality (a "personality option")
NSMapTableCopyIn (a "copy option")
NSMapTableStrongMemory是默认的“memory option”。然而,默认的“personality option”,默认“copy in”的行为没有名字那么这两个值可以被视为隐含在列表中。

memory option

Objective-C使用“strong”和“week”作为垃圾回收机制相关的术语,它可能不是很明显,这些选项可以在垃圾回收机制代码之外使用(苹果称它为手动内存管理)。
在垃圾回收机制外,他们被定义为:
strong: 使用 retain 和 release
weak: 不使用 retain 和 release
NSMapTable只允许NSPointerFunctionsOptions对应的Objective-C对象“personality option”。还有其他NSPointerFunctionsOptions “personality option”里的“strong”指针的行为不包括retain和release,但这些选项在NSMapTable都是不允许的。

关于使用垃圾回收机制的“week”之外的警告:

指针将不会被归零如在垃圾回收环境所以你必须要小心,不要取消引用指针,如果它被释放。

Personality options

该NSMapTableObjectPointerPersonality选项用来控制是否isEqualTo:和哈希对象中的方法添加的对象添加到集合时使用。
NSMapTableObjectPointerPersonality指定

对象的指针的值是用于直接比较和位移哈希生成(isEqualTo:和散列方法是不使用)。
NSMapTableObjectPointerPersonality 不指定(默认行为)

的哈希值与isEqualTo:方法会在调用的关键在确定的存储位置NSMapTable。这些方法的返回值不应改变(是不可变)为主要用在时间NSMapTable。
两行为暗示内容实现了
NSObject
的协议,所以在这个协议方法也可以在key和object调用。特别地,描述的方法可以在被调用NSMapTable包含密钥和对象无论使用的“Personality
options”。该
NSMapTable
将只支持NSCoding如果所有的key和object实现了NSCoding协议了。

Copy options

如果NSMapTableCopyIn被指定,当
NSCopying
协议被加入时
NSMapTable
使用使自己的数据副本。如果不指定此选项(默认行为)将不会复制。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: