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就不会。

NSDictionary 的内部实现的更多相关文章

  1. 非等高cell实战(01)-- 实现微博页面

    非等高cell实战(01)-- 实现微博页面 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战来整合一下. 首先看一下效果图: 需求分析 此页面为非等 ...

  2. (转)ios error:unrecognized selector sent to class

    转自:http://blog.itpub.net/12231606/viewspace-1081952/ 今天将app统计的.a静态库包含到一个app应用中,调试时报下面的错误: *** Termin ...

  3. 非等高cell实战--实现微博页面

    代码地址如下:http://www.demodashi.com/demo/11639.html 前言 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战 ...

  4. iOS - error:unrecognized selector sent to class 导入第三方SDK .a后不识别,运行崩溃

    今天将app统计的.a静态库包含到一个app应用中,调试时报下面的错误: *** Terminating app due to uncaught exception 'NSInvalidArgumen ...

  5. KVO内部实现原理

    KVO的原理: 只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象, (格式如:NSKVONotifying_className), 并且重写自动生成的子类对象的被监听 ...

  6. KVO的内部实现原理

    kvo概述 kvo,全称Key-Value Observing,它提供了一种方法,当对象某个属性发生改变时,允许监听该属性值变化的对象可以接受到通知,然后通过kvo的方法响应一些操作. kvo实现原理 ...

  7. OC:属性的内部实现原理、dealloc内释放实例变量、便利构造器方法的实现原理、collection的内存管理

    代码: // // main.m #import <Foundation/Foundation.h> #import "Person.h" #import " ...

  8. NSDictionary所有API的学习。

    <欢迎大家增加iOS开发学习交流群:QQ529560119> @property (readonly)NSUInteger count; //1.利用指定的key寻找相应的value - ...

  9. NSDictionary实现原理-ios哈希hash和isEqual

    NSDictionary实现原理-ios哈希hash和isEqual   OC中自定义类的NSCopying实现的注意事项(isEqual & hash实现) http://blog.csdn ...

随机推荐

  1. C#:继承多态的方法实现数的简单加减乘除运算

       // 定义一个抽象的父类     abstract class Figure     {         //声明抽象方法:         //父类中的所有家里人可以用的方法必须都应用到子类中 ...

  2. Uva 10780 Again Prime? No Time.(分解质因子)

    题意:给你两个数m和n,问 n! 可以被 m^k 整除的k的最大值 思路:从这道我们可以想到n!末尾有多少个0的问题,让我们先想一下它的思想,我们找 n! 末尾有多少0, 实际上我们是在找n!中5的个 ...

  3. 遍历json创建树状表(首先的前提条件是要引入jquery的jquery treeTable插件)

    "root":{ "children":[ { "name":"AA", "children":[ ...

  4. 编译 ORB_SLAM2 (一)

    之前有记录关于ORB_SLAM的第一个版本的编译,每次就是要编译程序,都会遇到很多问题,并不是所谓的按照教程来就一定能编译成功,所以这一次编译也遇到了很多问题.百度的时候也看到网上有很多相似的问题,但 ...

  5. vim - 自动补齐

    OmniComplete是基于ctags的,所以要先安装ctags 到http://www.vim.org/scripts/script.php?script_id=2358下载cpp_src.tar ...

  6. Ubuntu 16.04上Docker使用手记

    一.Docker Hub的使用Docker Hub是Docker官方维护的仓库,里面已经包含了很多的镜像,一般我们的需求直接在官方仓库搜索就可以得到解决.在官方的公共仓库中我们无需登录就可以进行镜像的 ...

  7. 学习笔记:shell 中 [-eq] [-ne] [-gt] [-lt] [ge] [le]

    -eq           //等于 -ne           //不等于 -gt            //大于 (greater ) -lt            //小于  (less) -g ...

  8. ansible role 执行顺序

    the dependencies of the 'openshift-master' role.- docker- openshif_common  - os_firewall   - openshi ...

  9. centos6.8安装superctl 后台管理工具

    下载安装python yum install python-setuptools 从官网下载supervisor包 https://pypi.python.org/pypi/supervisor 解压 ...

  10. IIS7添加mp4 MINE类型报错:无法写入配置文件

    解决方法: 方法一: 可能是由于文件为只读属性,所以修改网站文件访问权限,把此文件夹或者文件的写入权限给了这个用户. 方法二: 可能由于网站目录所在的分区是fat32格式,所以要把网站目录放在NTFS ...