iOS NSDictionary除了NSString 类型外还有什么类型可以作为key

在iOS中,只要是不为nil的OC不可变对象类型都可以作为NSDictionary的KeyType。比如NSNumber,NSArray,NSMutableArray,NSDictionary等等。但是自定义对象作为key的时候必须遵守协议并实现其协议方法- (id)copyWithZone:(NSZone *)zone,如下:

- (id)copyWithZone:(NSZone *)zone{
    //这里必须是self本身对象,具体原因请下翻
    return self;
}

一、探究

  • 首先任意对象可以作为NSDictionary的Value。这个我相信大家已经熟烂于心。所以下边的示例中,NSDictionary的Value我只用了一个字符串。

  • NSNumber作为Key进行试验


    NSNumber.png
  • NSArray作为Key进行试验


    NSArray.png
  • NSDictionary作为Key进行试验


    NSDictionary.png
  • NSMutableArray作为Key进行试验


    NSMutableArray.png
  • 自定义对象作为Key进行试验(记得实现copyWithZone

    image.png

二、原理

  • NSDictionary苹果系统实现原理

Objective-C 中的字典 NSDictionary 底层其实是一个哈希表,实际上绝大多数语言中字典都通过哈希表实现。
NSDictionary是使用 hash表来实现key和value之间的映射和存储的, hash函数设计的好坏影响着数据的查找访问效率。数据在hash表中分布的越均匀,其访问效率越高。而在Objective-C中,通常都是利用NSString 来作为键值,其内部使用的hash函数也是通过使用 NSString对象作为键值来保证数据的各个节点在hash表中均匀分布。
字典每个条目存取是通过将字典的键(Key)计算出键的hash值,通过查hash表获取具体的value。所以作为NSDictionary 的键(Key)取值的时候,只要其key对象内容地址相同就可以取出相应的值。(PS:地址不同,对象相同的遵守协议的key也可以取出对应的value)。

  • 从官方文档一些细节中体现

- (void)setObject:(ObjectType)anObject forKey:(KeyType )aKey

从这个方法中可以知道, 要作为 Key 值,必须遵循 NSCopying 协议。也就是说在NSDictionary内部,会对 aKey 对象 copy 一份新的。而 anObject 对象在其内部是作为强引用(retain或strong)。所以在MRC下,向该方法发送消息之后,我们会向anObject发送 release 消息进行释放

三、注意事项

1.自定义对象作为key必须遵守协议并实现其协议方法- (id)copyWithZone:(NSZone *)zone . 切记 切记 切记!

- (id)copyWithZone:(NSZone *)zone{
    
    return self;
}

2.尽量使用NSString

  • 一般来说,如果你用苹果的plist来储存文件的话,那么key只能是NSString格式,使用NSNumber格式的话,-writeToFile是写不进去的,会返回值NO
  • Classes such as NSString that are part of Foundation have a good hash function.

3.苹果的官方文档(部分摘要)指出:

A key can be any object that adopts the NSCopying protocol and implements the
 hash and isEqual: methods.

If the key objects have a good hash function, accessing an element, 
setting an element, and removing an element all take constant time. With a poor
hash function (one that causes frequent hash collisions), these operations 
take up to linear time. Classes such as `NSString` that are part of Foundation 
have a good hash function.
笔者拙劣的翻译:

OC对象作为字典的Key需要遵守NSCopying协议并且实现hashisEqual两个方法。

如果有一个好的hash性能的OC对象作为字典的Key,当访问、修改、移除一个条目所耗费的时间都是基本固定的。如果作为key的对象的hash性能很低(就是hash值经常冲突),上边那些操作所耗费的时间将呈先行增长。举个例子来说,Foundation 框架中的NSString的hash性能就很不错。

  • 上边我提到的说是必须(注意是必须)遵守协议并实现(id)copyWithZone:(NSZone *)zone。这是保证程序不会一运行就crash。更完备性的就是如官网文档第三段所说将isEqualhash两个方法一起重写。
  • NSDictionary苹果官网链接

4.有些朋友可能阅读上边例子的时候对 @[] 或者@{}作为Key会有一些疑问

@[]、@{}、@3 这三个快捷类型在内存中的地址只有一份。所以上边可以正常的取出值。


地址一样

如果您有什么疑问或者书写歧义,非常感激您能留言~

你可能感兴趣的:(iOS NSDictionary除了NSString 类型外还有什么类型可以作为key)