NSDictionary的内部实现

NSDictionary是IOS中使用的一种key-value容器,参考cocotron的源代码,NSDictionary使用NSMapTable实现。

NSMapTable同样是一个key-value的容器,下面是NSMapTable的部分代码:

typedef struct {

NSMapTable        *table;

NSInteger                i;

struct _NSMapNode *j;

} NSMapEnumerator;

上述结构体描述了遍历一个NSMapTable时的一个指针对象,其中包含table对象自身的指针,计数值,和节点指针。

typedef struct {

NSUInteger (*hash)(NSMapTable *table,const void *);

BOOL (*isEqual)(NSMapTable *table,const void *,const void *);

void (*retain)(NSMapTable *table,const void *);

void (*release)(NSMapTable *table,void *);

NSString  *(*describe)(NSMapTable *table,const void *);

const void *notAKeyMarker;

} NSMapTableKeyCallBacks;

上述结构体中存放的是几个函数指针,用于计算key的hash值,判断key是否相等,retain,release操作。

typedef struct {

void      (*retain)(NSMapTable *table,const void *);

void      (*release)(NSMapTable *table,void *);

NSString  *(*describe)(NSMapTable *table, const void *);

} NSMapTableValueCallBacks;

上述存放的三个函数指针,定义在对nsmaptable插入一对key-value时,对value对象的操作。

@interface NSMapTable : NSObject {

NSMapTableKeyCallBacks  *keyCallBacks;

NSMapTableValueCallBacks *valueCallBacks;

NSUInteger            count;

NSUInteger            nBuckets;

struct _NSMapNode  **buckets;

}

上面是NSMtabtable真正的描述,可以看出来NSMapTable是一个哈希+链表的数据结构,因此在NSMapTable中插入或者删除一对对象时

寻找的时间是O(1)+O(m),m最坏时可能为n。

O(1):为对key进行hash得到bucket的位置

O(m):遍历该bucket后面冲突的value,通过链表连接起来。

因此:NSDictionary中的key Value遍历时是无序的,至如按照什么样的顺序,跟hash函数相关。NSMapTable使用NSObject的哈希函数。

-(NSUInteger)hash {

return (NSUInteger)self>>4;

}

上述是NSObject的哈希值的计算方式,简单通过移位实现。右移4位,左边补0.

因为对象大多存于堆中,地址相差4位应该很正常。

@implementation NSDictionary (NSKeyValueCoding)

-(id)valueForKey:(NSString*)key;

{

if([key hasPrefix:@"@"])

return [super valueForKey:[key substringFromIndex:1]];

return [self objectForKey:key];

}

-(void)setValue:(id)value forKey:(NSString*)key

{

[NSException raise:NSInvalidArgumentException format:@"%@ called on immutable dictionary %@", NSStringFromSelector(_cmd), self];

}

@end

@implementation NSMutableDictionary (NSKeyValueCoding)

-(void)setValue:(id)value forKey:(NSString*)key

{

if(value)

[self setObject:value forKey:key];

else

[self removeObjectForKey:key];

}

@end

使用setObject:ForKey时很可能因为value或者key为空导致crash,使用setValue:Forkey就不会。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 5,865评论 0 9
  • 蓝花鼠尾草别名:粉萼鼠尾草、一串蓝、 蓝丝线。 鼠尾草属,唇形科。多年生草本,植株呈丛生状,植株被柔毛。茎为四角柱...
    王了一一阅读 5,680评论 15 14
  • 没有人会永远忍受你的小性子。 不要把自己看太重,因为摔倒之后,没有谁会愿意分担你的痛。 你只有自己变强大,再痛也要...
    莫然等等阅读 1,108评论 0 0
  • 好啦,这次我也不多废话啦 直接进主题吧 这次分别从游戏的简介,剧情,美术,玩法设计,营销套路和一些小缺点来分析这款...
    孑汪汪阅读 12,783评论 2 22
  • 儿子的抱怨 小W的儿子晚上回家满脸的不高兴,在妈妈的追问下,儿子甩出一句“夏某某是我们班令人最讨厌的女生!” 小W...
    傻人和童话阅读 1,675评论 0 0

友情链接更多精彩内容