NSDictionary and NSMutableDictionary
0,铺垫
做程序员早期,我对各种编程语言提供的、类似于“STL”这样的API有一种不信任感,总觉得那是把简单的事情搞复杂。
后来维护了一个项目(2004年),该项目用C++编写,用了一些STL中的vector、iterator一类的东西,首次感受到用STL实现一些基础数据结构操作的便利性。
但头脑中的不信任感并没有完全去除,在接下来的三年,由于主要使用C语言,所以依然用最底层代码自己写单、双向链表,哈希表,FIFO队列,长度自增数组。
在一次项目升级前(2006年),关于是否用C++替换C引起了争论,当时我是Linux迷,所以坚定的站在Linus Tovard这边选择了C,最终C阵营获胜,原因是:1、无切换成本。2、效率稍高。于是又失去了一次拥抱变化的机会。
这次做iOS下一个数据管理的软件处理数据缓存,既要有非常好快的单条记录访问速度,用来更新记录内容,又要能快速返回有序的子数据集。经过简单思考后,决定用NSDictionary来作为根容器缓存数据。没想到随着使用越来越深入,对它的了解越来越多,我发现已经渐渐爱上了它。。。
废话扯完,讲讲NSDictionary的一些特性(以下不区别NSDictionary和NSMutableDictionary):
1,NSDictionary使用Hash表实现Key/Object存储。
Hash表是一种访问速度很快的数据结构,前提是Hash函数设计合理,能够使数据在各个子节点均匀分布,这一点使用NSString对象可以保证,这是文档中的说明:
Classes such as NSString that are part of Foundation have a good hash function.
2,NSDictionary对于Key和Object的处理方式不同。
setObject:(id)object forKey:(id)key 是NSDictionary常用的message接口,第一个参数是你要存储的对象,第二个参数用来生成Hash入口(一般用NSString对象)。
key必须遵从NSCopying协议,在调用时,NSDictionary会在内部创建一个具有相同内容的内存对象,并不会引用key。
object对象却不然,NSDictionary在内部对它进行了强引用(想想ARC中的strong),也就意味着两个指针指向同一个地址,所以你可以写这样的代码:
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
NSMutableArray * array = [[NSMutableArray alloc] init];
[dict setObject:array forKey:@"kArrayValue"];
[array addObject:@"FirstObject"];
将array插入到dict后,继续修改array的内容,相当于修改dict中存储的内容。
3,除了NSString,还能使用其它类型的对象作为key吗?
可以,但必须继承自NSObject,并且必须重载hash和isEqual:两个消息处理接口。
hash:计算该对象的hash值,用来定位Hash表入口。所以请写一个分布均匀的hash函数。
isEqual:通过hash值定位的Hash表入口可能有多个具有相同hash值的对象,所以在访问数据时要通过这个函数来找到相等的对象。
4,简单后记。
除了以上三点以外,我还曾为一个问题纠结过,看下面的情况:
NSString * key1 = @"123";
int a = 123;
NSString * key2 = [NSString stringWithFormat:@"%d”, a];
key1和key2有相同的内容(都是“123”),但他们是不同的对象,所以他们的hash值相同吗?如果不同就麻烦了。
好在他们的hash值是一样的,因为在NSString的文档中,搜索“hash”,你可以看到下面的话:
If two string objects are equal (as determined by the isEqualToString: method), they must have the same hash value.
The abstract implementation of this method fulfills this requirement, so subclasses of NSString shouldn’t override it.
所以使用一些高级数据结构,并非一定会降低效率,但肯定会提高代码的健壮性,前提是按照要求合理的使用它。回想那些年写“单、双向链表,哈希表,FIFO队列,长度自增数组”的岁月,泪流满面。