KVC的底层实现

Objective-C里面的Key-Value Observing (KVO)机制,非常不错,可以很好的减少浇水代码。关于KVO的学习,可以参考文章:《Key-Value Observing快速入门》:http://www.cocoadev.cn/Objective-C/Key-Value-Observing-Quick-Start-cn.asp

KVO概念:

     KVO是cocoa中的一个核心概念,简单理解就是:关注Model某个数据(Key)的对象可以注册为监听器,一旦Model某个Key的Value发生变化,就会广播给所有的监听器

KVO机制:

KVO(Key Value Observe)是cocoa中用来设值或取值的协议(NSKeyValueCoding),跟java的ejb有点类似,通过对变量和函数名进行规范达 到方便设置类成员值的目的。它有点类似于Notification,但是,它提供了观察某一属性变化的方法,而Notification需要一个发送 notification的对象,这样KVO就比Notification极大的简化了代码。

这种观察-被观察模型适用于这样的情况,比方说根据A(数据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用价值很高。

Key-Value Coding(KVC)实现分析

KVC运用了一个isa-swizzling技术。isa-swizzling就是类型混合指针机制。KVC主要通过isa- swizzling,来实现其内部查找定位的。isa指针,如其名称所指,(就是is a kind of的意思),指向维护分发表的对象的类。该分发表实际上包含了指向实现类中的方法的指针,和其它数据。

比如说如下的一行KVC的代码:

[site setValue:@"sitename" forKey:@"name"];
就会被编译器处理成:

SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (site->isa,sel);
method(site, sel, @"sitename", @"name");

    首先介绍两个基本概念:

(1)SEL数据类型:它是编译器运行Objective-C里的方法的环境参数。

(2)IMP数据类型:他其实就是一个编译器内部实现时候的函数指针。当Objective-C编译器去处理实现一个方法的时候,就会指向一个IMP对象,这个对象是C语言表述的类型。

关于如何找到实现函数的指针,可参考文章:《Objective-C如何避免动态绑定,而获得方法地址》:http://www.cocoadev.cn/Objective-C/Get-method-address.asp

这下KVC内部的实现就很清楚的清楚了:一个对象在调用setValue的时候,(1)首先根据方法名找到运行方法的时候所需要的环境参数。(2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。(3)再直接查找得来的具体的方法实现。

Key-Value Observing(KVO)实现

在上面所介绍的KVC机制上加上KVO的自动观察消息通知机制就水到渠成了。

当观察者为一个对象的属性进行了注册,被观察对象的isa指针被修改的时候,isa指针就会指向一个中间类,而不是真实的类。所以isa指 针其实不需要指向实例对象真实的类。所以我们的程序最好不要依赖于isa指针。在调用类的方法的时候,最好要明确对象实例的类名。

熟悉KVO的朋友都知道,只有当我们调用KVC去访问key值的时候KVO才会起作用。所以肯定确定的是,KVO是基于KVC实现的。其实看了上面我们的分析以后,关系KVO的架构的构思也就水到渠成了。

因为KVC的实现机制,可以很容易看到某个KVC操作的Key,而后也很容易的跟观察者注册表中的Key进行匹对。假如访问的Key是被观察的Key,那么我们在内部就可以很容易的到观察者注册表中去找到观察者对象,而后给他发送消息。

=======================================================

对kvo/kvc做了简单的介绍,可作为入门读物。

有些术语描述不够精确请指正。

欢迎讨论。

KVO是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数 据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。

适用kvo时,通常遵循如下流程:

1 注册:

-(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context

keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)

2 实现变化方法:

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context

change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。

是不是很简单?kvo的逻辑非常清晰,实现步骤简单。

说了这么多,大家都要跃跃欲试了吧。可是,在此之前,我们还需要了解KVC机制。其实,知道了kvo的逻辑只是帮助你理解而已,要真正掌握的,不在 于kvo的实现步骤是什么,而在于KVC,因为只有符合KVC标准的对象才能使用kvo(强烈推荐要使用kvo的人先理解KVC)。

KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor方法或是直接访问成员对象。

key就是确定对象某个值的字符串,它通常和accessor方法或是变量同名,并且必须以小写字母开头。Keypath就是以“.”分隔的key,因为属性值也能包含属性。比如我们可以person这样的key,也可以有key.gender这样的key path。

获取属性值时可以通过valueForKey:的方法,设置属性值用setValue:forKey:。与此同时,KVC还对未定义的属性值定义了 valueForUndefinedKey:,你可以重载以获取你要的实现(补充下,KVC定义载NSKeyValueCoding的非正式协议里)。

在O-C 2.0引入了property,我们也可以通过.运算符来访问属性。下面直接看个例子:

@property NSInteger number;

instance.number = 3;

[instance setValue:[NSNumber numberWithInteger:3] forKey:@"number"];

注意KVC中的value都必须是对象。

以上介绍了通过KVC来获取/设置属性,接下来要说明下实现KVC的访问器方法(accessor method)。Apple给出的惯例通常是:

-key:,以及setKey:(使用的name convention和setter/getter命名一致)。对于未定义的属性可以用setNilValueForKey:。

至此,KVC的基本概念你应该已经掌握了。之所以是基本,因为只涉及到了单值情况,kvc还可以运用到对多关系,这里就不说了,留给各位自我学习的空间

接下来,我们要以集合为例,来对掌握的KVC进行一下实践。

之所以选择array,因为在ios中,array往往做为tableview的数据源,有这样的一种情况:

假设我们已经有N条数据,在进行了某个操作后,有在原先的数据后多了2条记录;或者对N中的某些数据进行更新替换。不使用KVC我们可以使用 reloadData方法或reloadRowsAtIndexPaths。前一种的弊端在于如果N很大消耗就很大。试想你只添加了几条数据却要重载之前 N数据。后一种方法的不足在于代码会很冗余,你要一次计算各个indexPath再去reload,而且还要提前想好究竟在哪些情况下会引起数据更新,

倘若使用了KVC/kvo,这样的麻烦就迎刃而解了,你将不用关心追加或是更新多少条数据。

下面将以添加数据为例,说明需要实现的方法:

实现insertObject:inKeyAtIndex:或者insertKey:atIndexes。同时在kvo中我们可以通过change这个dictionary得知发生了哪种变化,从而进行相应的处理。

http://www.cocoadev.cn/Objective-C/Key-Value-Observing-Quick-Start-cn.asp

KVO与Notification之间的区别:

notification是需要一个发送notification的对象,一般是notificationCenter,来通知观察者。

KVO是直接通知到观察对象,并且逻辑非常清晰,实现步骤简单。

时间: 2024-08-07 19:21:32

KVC的底层实现的相关文章

KVC的底层实现原理

KVC是OC特有的,本质是在运行时动态的给对象发送setValue:forKey 消息,设置数值 -调用super.init 保证对象已经被创建完成 .当给对象发送setValue:forKey 消息时要判断对象是否存在key所对应的属性,直接赋值 如果没有就调用undefinedKey(默认崩溃,需要重写) setValue:forKey的调用顺序首先会寻找set<key>方法,如果没有就去找_<key>  _is<Key>  <key> is<ke

(知其所以然 主题3)论观察者模式之KVC和KVO

在开发的时候,是不是忽然有种错觉:我们好像是代码的搬运工,一个项目开始,把自己写好的.封装好的类.框架亦或别人写好的第三方框架不假思索的运用到项目中,一方面:项目时间紧:二方面:简单好用,减少了代码量.但是有时候,我们是否应该停下脚步, 从底层去看看代码的世界,那样我们收益会颇丰,让我们一起走在学习的路上吧! 在开发中,有很多地方都需要对KVC和KVO进行运用.我们只知道这是Object-C提供的一个不错的机制,可以很好的减少代码:但是我们可能不会过多的去了解它底层是如何实现的,下面,我们一起来

iOS开发各种底层实现--面试必备!

iOS开发常用技术底层实现(精简概述) 本章将对ios开发技术底层实现的总结,其实关于ios开发中各种底层的实现,网上相关文章多到数不过来,而不且非常不错,我也没有自信我能比他们做的更好,因为毕竟每个人专研的东西不一样,本文主要正对三类用户! 资深的ios开发者,对底层做过专门研究,但是没有一个系统整理,或者说不能很清楚的表达. ios开发初学者,没有专门研究过底层或者相关源码的初学者,但是不太建议一开始就看,因为如果你没有过一点接触,看了也看不懂,或者看了也白看,最多就是留个印象在脑子了,对初

UIPickView 和 UIDatePicker

*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } a { color: #4183C4; } a.absent { color: #cc0000; } a.anchor { display: block; padding-left: 30px; margin-left: -30px; cursor: pointer; position: absolute

微博项目笔记

微博笔记: 1.LaunchScreen /* *LaunchScreen:替代以前的启动图片 *好处: *1.可以展示更多的内容 *2.仅仅需要一张大尺寸的图片就好,然后伸缩适应图片 * *启动的优先级: *启动图片的优先级低于 < LaunchScreen (图片不适合时记得调一下伸缩) * * 当模拟器尺寸不对的时候,第一时间找启动图片,模拟器的尺寸由启动图片决定(使用启动图片不用Xib的时候记得调整Info.plist 加载launchScreen的名称删掉) */ 2.--------

iOS 面试题一

iOS常见面试题总结(一) 字数2901 阅读403 评论6 喜欢35 一.沙盒 沙盒本质上是一个文件夹,是iOS平台针对每一个安装的的应用在本地生成的一个文件夹,(沙盒文件夹的名字是随机产生的)应用只能访问自身的沙盒文件夹内的内容. 沙盒文件夹下包含三个文件夹: (1).Document:存储持久化的数据,想要长久存储的信息存储在该文件夹下,但是该文件夹不要太大,不然上传审核通过不了 Library (1)Caches:存放缓存文件,下载的音频,视频,图片,小说 (2)Preferences:

【2017年最新】iOS面试题及答案

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px "PingFang SC Semibold"; color: #464646 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px "PingFang SC"; min-height: 21.0px } p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px

iOS之KVC字典转模型的底层实现

KVC: Key Value Coding (键值编码) 在iOS开发中,KVC是我们经常要使用的技术.那么KVC有什么作用呢?简单列举一下下面几种: 取值和赋值(开发中基本不用) 获取对象私有变量的值.(经常使用,例如UIPageContorl分页, 设置圆点为图片) 改变对象私有变量的值(经常使用) 简单的字典转模型(偶尔使用) 模型转字典 批量取值 KVC字典转模型的底层实现 通常我们手动将字典转模型的话,会在模型中提供一个类方法接收一个字典,在这个方法中将字典转换成模型,再将转换好的模型

iOS 的 KVC &amp; KVO的底层实现原理

KVO 内部实现原理 1. KVO 是基于runtime机制实现的. 2. 当某个类的对象第一次被观察时,系统就会在运行期动态的创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法; 派生类在被重写的setter方法中实现真正的通知机制 (Person -> NSKVONotifying_Person) 1.KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性.而不是通过调用Setter.Getter方法访问.