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)对象可以注册为监听器。一旦ModelKey的Value发生变化,它将广播给所有监听器
KVO机制:
KVO(Key Value Observe)在cocoa中,用于设值或取值的协议(NSKeyValueCoding),有点像java的ejb,通过规范变量和函数名 设置类成员值的目的很方便。它有点像Notification,但它提供了观察属性变化的方法,而Notification需要发送 对象notification,这样KVO就比notification大大简化了代码。
这种观察-被观察模型适用于这种情况,例如根据A(数据类)的属性值变化,B(view类)中的某一属性发生了相应的变化。kvo应用对于推崇MVC的cocoa具有很高的价值。
Key-Value Coding(KVC)实现分析
KVC采用isa-swizling技术。isa-swizling是类型混合指针机制。KVC主要通过isaaaac-swizzling,实现其内部搜索定位。isa指针,如其名称所指(即isa指针) 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-如何避免动态绑定并获得方法地址?:http://www.cocoadev.cn/Objective-C/Get-method-address.asp
现在KVC的内部实现非常清楚:当一个对象呼叫setvalue时,(1)首先根据方法名找到操作方法所需的环境参数。(2)他将从isa指针和环境参数中找到具体方法实现的接口。(3)然后直接找到具体的实现方法。
Key-Value Observing(KVO)实现
将KVO的自动观察信息通知机制添加到上述KVC机制中是很自然的。
当观察者注册一个对象的属性并修改被观察对象的isa指针时,isa指针将指向中间类,而不是真实类。因此,isa指针不需要指向实例对象的真实类别。因此,我们的程序最好不要依赖isa指针。在调用类别方法时,最好明确对象实例的类别名称。
熟悉KVO的朋友都知道,只有当我们调用KVC访问KVO时,KVO才会工作。因此,必须肯定的是,KVO是基于KVC实现的。事实上,在阅读了上述分析后,关系KVO结构的概念是自然的。
由于KVC的实现机制,很容易看到KVC操作的Key,然后也很容易匹配观察者注册表中的Key。如果访问的Key是观察的Key,那么我们可以很容易地在观察者注册表中找到观察者对象,然后给他发送信息。
=======================================================
对kvo/kvc做了一个简单的介绍,可以作为入门读物。
有些术语描述不够准确,请指正。
欢迎讨论。
KVO是Cocoa的一个重要机制,它提供了观察某个属性变化的方法,极大地简化了代码。这种观察-这种情况适用于被观察模型,例如根据A(数据类)的属性值变化,B(view类)中的某一属性发生了相应的变化。kvo广泛应用于推崇MVC的cocoa。
在适用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)objectchange:(NSDictionary *)change context:(void*)context
change存储了一些变化的数据,如变化前的数据和变化后的数据;如果context在注册时不是空的,可以在这里接收context。
是不是很简单?kvo逻辑清晰,实现步骤简单。
说了这么多,每个人都渴望尝试它。然而,在此之前,我们仍然需要了解KVC机制。事实上,知道KVO的逻辑只是为了帮助你理解它。真正掌握的不是 kvo的实现步骤是什么,而是kvc,因为只有符合kvc标准的对象才能使用kvo(强烈建议使用kvo的人先了解kvc)。
KVC是一种间接访问对象属性(用字符串表示)的机制,而不是直接调用对象的accesor方法或直接访问成员对象。
key是确定对象值的字符串。它通常与accesor方法或变量相同,必须从小写字母开始。keypath是“.“分离的key,因为属性值也可以包含属性。例如,我们可以像person这样的key,也可以有key.像gender这样的keyy 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个数据,在某个操作之后,在原始数据之后有两个记录;或者更新和替换N中的一些数据。不使用KVC,我们可以使用reloaddata方法或reloadrowsatindexpaths。前者的缺点是,如果N消耗很多,它就会消耗很多。想象一下,你只添加了几个数据,但你必须重载以前的N数据。后一种方法的缺点是代码会非常冗余。在去reload之前,你必须计算每个indexPath,并提前考虑在什么情况下会导致数据更新,
如果使用KVC//kvo,这样的麻烦很容易解决,你不必关心有多少数据被添加或更新。
以添加数据为例,说明需要实现的方法:
insertobjecttect实现:inKeyAtIndex:或者insertKey:atIndexes。同时,在kvo中,我们可以通过dictionarychange知道发生了什么变化,从而进行相应的处理。
http://www.cocoadev.cn/Objective-C/Key-Value-Observing-Quick-Start-cn.asp
KVO和Notification的区别:
notification是一个需要发送notification的对象,通常是notificationcenter通知观察者。
KVO直接通知观察对象,逻辑非常清晰,实现步骤简单。
对kvo/kvc做了一个简单的介绍,可以作为入门读物。
有些术语描述不够准确,请指正。
欢迎讨论。
KVO是Cocoa的一个重要机制,它提供了观察某个属性变化的方法,极大地简化了代码。这种观察-这种情况适用于被观察模型,例如根据A(数据类)的属性值变化,B(view类)中的某一属性发生了相应的变化。kvo广泛应用于推崇MVC的cocoa。
在适用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)objectchange:(NSDictionary *)change context:(void*)context
change存储了一些变化的数据,如变化前的数据和变化后的数据;如果context在注册时不是空的,可以在这里接收context。
是不是很简单?kvo逻辑清晰,实现步骤简单。
说了这么多,每个人都渴望尝试它。然而,在此之前,我们仍然需要了解KVC机制。事实上,知道KVO的逻辑只是为了帮助你理解它。真正掌握的不是 kvo的实现步骤是什么,而是kvc,因为只有符合kvc标准的对象才能使用kvo(强烈建议使用kvo的人先了解kvc)。
KVC是一种间接访问对象属性(用字符串表示)的机制,而不是直接调用对象的accesor方法或直接访问成员对象。
key是确定对象值的字符串。它通常与accesor方法或变量相同,必须从小写字母开始。keypath是“.“分离的key,因为属性值也可以包含属性。例如,我们可以像person这样的key,也可以有key.像gender这样的keyy 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个数据,在某个操作之后,在原始数据之后有两个记录;或者更新和替换N中的一些数据。不使用KVC,我们可以使用reloaddata方法或reloadrowsatindexpaths。前者的缺点是,如果N消耗很多,它就会消耗很多。想象一下,你只添加了几个数据,但你必须重载以前的N数据。后一种方法的缺点是代码会非常冗余。在去reload之前,你必须计算每个indexPath,并提前考虑在什么情况下会导致数据更新,
如果使用KVC//kvo,这样的麻烦很容易解决,你不必关心有多少数据被添加或更新。
以添加数据为例,说明需要实现的方法:
insertobjecttect实现:inKeyAtIndex:或者insertKey:atIndexes。同时,在kvo中,我们可以通过dictionarychange知道发生了什么变化,从而进行相应的处理。