NSDictionary实现原理

       NSDictionary(字典)是使用 hash表来实现key和value之间的映射和存储的, hash函数设计的好坏影响着数据的查找访问效率。数据在hash表中分布的越均匀,其访问效率越高。而在Objective-C中,通常都是利用NSString 来作为键值,其内部使用的hash函数也是通过使用 NSString对象作为键值来保证数据的各个节点在hash表中均匀分布。

见NSDictionary中最常用的一个方法原型:

- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey;

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

既然知道了作为 key 值,必须遵循 NSCopying 协议,说明除了 NSString 对象之外,我们还可以使用其他类型对象来作为 NSDictionary 的 key值。不过这还不够,作为 key 值,该类型还必须继承于 NSObject 并且要重载一下两个方法:

- (NSUInteger)hash;

- (BOOL)isEqual:(id)object;

其中,hash 方法是用来计算该对象的 hash 值,最终的 hash 值决定了该对象在 hash 表中存储的位置。所以同样,如果想重写该方法,我们尽量设计一个能让数据分布均匀的 hash 函数。

isEqual 方法是为了通过 hash 值来找到 对象 在hash 表中的位置。

下面,我根据一个小Demo来自定义一个作为 NSDictionary 的 key 值的类。见代码:

KeyObject.h文件:

//
//  KeyObject.h
//  KeyDemo
//
//  Created by linshaolie on 14-11-26.
//  Copyright (c) 2014年 lin. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface KeyObject : NSObject<NSCopying>  //实现Copying协议

//作为hash值
@property(nonatomic, readonly) NSUInteger hashValue;

- (instancetype)initWithHashI:(NSUInteger)i;

@end
KeyObject.m文件:

//
//  KeyObject.m
//  KeyDemo
//
//  Created by linshaolie on 14-11-26.
//  Copyright (c) 2014年 lin. All rights reserved.
//

#import "KeyObject.h"

@interface KeyObject ()

//作为hash值
@property(nonatomic) NSUInteger hashValue;

@end

@implementation KeyObject


- (instancetype)initWithHashValue:(NSUInteger)hashValue
{
    self = [super init];
    if ( self )
    {
        _hashValue = hashValue;
    }
    return self;
}

#pragma mark -overload methor
- (BOOL)isEqual:(id)object
{
    //根据hash值判断是否是同一个键值
    return ([self hashKeyValue] == [(typeof(self))object hashKeyValue]);
}

- (NSUInteger)hash
{
    return [self hashKeyValue];     //返回哈希值
}

#pragma mark -NSCopying
- (id)copyWithZone:(NSZone *)zone
{
    KeyObject *obj = [KeyObject allocWithZone:zone];
    obj.hashValue = self.hashValue;
    return obj;
}

#pragma mark -private methor
//哈希函数
- (NSUInteger)hashKeyValue
{
    return _hashValue % 7;      //这里哈希函数用了简单的对7取余
}

@end

ViewController.m文件:(测试)

//
//  ViewController.m
//  KeyDemo
//
//  Created by lin on 14-11-26.
//  Copyright (c) 2014年 linshaolie. All rights reserved.
//

#import "ViewController.h"
#import "KeyObject.h"

@interface ViewController ()
{
    CGPoint _oldPoint;
    CGMutablePathRef _pathRef;
    UIImageView *_imageView;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //Test...
    KeyObject *key1 = [[KeyObject alloc] initWithHashValue:1];
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
    [dic setObject:@"AAA" forKey:key1];
    
    KeyObject *key2 = [[KeyObject alloc] initWithHashValue:8];
    [dic setObject:@"BBB" forKey:key2];
    
    KeyObject *key3 = [[KeyObject alloc] initWithHashValue:3];
    [dic setObject:@"CCC" forKey:key3];
    
    
    NSLog(@"%@", [dic objectForKey:key2]);
    NSLog(@"%@", [dic allKeys]);
    NSLog(@"%@", [dic allValues]);
}
@end

输出结果:


在调用 setObject: forKey:  后,内部会去调用 key 对象的 hash 方法确定 object 在hash表内的入口位置,然后会调用 isEqual 来确定该值是否已经存在于 NSDictionary中。






  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值