KVO/KVC 实现机理分析

发布时间:2023-05-16 09:20:58

  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知道发生了什么变化,从而进行相应的处理。

上一篇 java中的字符流可以读取word文件内容吗 java 字符串流
下一篇 由system.currentTimeMillis() 获得当前的时间

文章素材均来源于网络,如有侵权,请联系管理员删除。

标签: Java教程Java基础Java编程技巧面试题Java面试题