KVC、KVO、NSNotification

2023-11-27 22:50
文章标签 kvc kvo nsnotification

本文主要是介绍KVC、KVO、NSNotification,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:杨登峰 (dengfengyang@gmail.com)
时间:2010-03-12
转帖请注明转之 苹果开发中文网(http://www.cocoadev.cn/Objective-C/KVO-20100222-0627.asp)
以上说明是本文不可分割的一部分。
Objective-C里面的Key-Value Observing (KVO)机制,非常不错,可以很好的减少浇水代码。关于KVO的学习,可以参考文章:《Key-Value Observing快速入门》:http://www.cocoadev.cn/Objective-C/Key-Value-Observing-Quick-Start-cn.asp
关于如何找到实现函数的指针,可参考文章:《Objective-C如何避免动态绑定,而获得方法地址》:
     http://www.cocoadev.cn/Objective-C/Get-method-address.asp
   参考:http://www.cocoachina.com/macdev/cocoa/2009/0611/221.htm
    http://www.cnblogs.com/dark-angel/archive/2011/05/05/2037734.html 
    http://www.cnblogs.com/pengyingh/articles/2367374.html

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

KVC(key value coding) 是一种间接访问对象属性(用字符串表征)的机制而不是直接调用对象的accessor方法或是直接访问成员对象 KVC运用了一个isa-swizzling技术。isa-swizzling就是类型混合指针机制。KVC主要通过isa-swizzling,来实现其内部查找定位的。isa指针,如其名称所指,(就是is a kind of的意思),指向维护分发表的对象的类。该分发表实际上包含了指向实现类中的方法的指针,和其它数据。

  1.KVC来获取/设置属性:

      key就是确定对象某个值的字符串,它通常和accessor方法或是变量同名, 

 并且必须以小写字母开头。Key path就是以“.”分隔的key,因为属性值也能包含属性。

 2.接下来要说明下实现KVC的访问器方法(accessor method)。

        Apple给出的惯例通常是:

      (1)-- [site setValue:@"sitename" forKey:@"name"];(使用的name convention和setter/getter命名一致)

       就会被编译器处理成:

        SEL sel = sel_get_uid ("setValue:forKey:"); SEL数据类型:它是编译器运行Objective-C里的方法的环境参数。
        IMP method = objc_msg_lookup (site->isa,sel);  IMP数据类型:他其实就是一个 编译器内部实现时候的函数指针。

                                                                                   当Objective-C编译器去处理实现一个方法的时候,就会指向一个IMP对象,

                                                                                 这个对象是C语言表述的类型(在Objective-C的编译器处理的时候,基本上都是C语言的)。

      method(site, sel, @"sitename", @"name");

       对于未定义的属性可以用setNilValueForKey:

        这下KVC内部的实现就很清楚的清楚了:一个对象在调用setValue的时候,首先根据方法名找到运行方法的时候所需要的环境参数。

         他会从自己isa指针结合环境参数,找到具体的方法实现的接口。再直接查找得来的具体的方法实现


      (2)--[site valueForKey:@"name": 当通过KVC调用对象时,比如:[self valueForKey:@”name”]时,

       程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有 name 这个方法,

       如果没找到,会继续查找对象是否带有name这个实例变量(iVar),

       不仅仅会查找name这个方法,还会查找getname这个方法,前面加一个get,或者_name以及_getname这几种形式

       同时,查找实例变量的时候也会不仅仅查找name这个变量,也会查找_name这个变量是否存在.

       如果还没有找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法

       如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

.KVO (key value observing)

1.机制概述

当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者.

2.优点

这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。

3.如何工作

需要三个步骤来建立一个属性的观察员。理解这三个步骤就可以知道KVO如何设计工作的。

 

(1)首先,构思一下如下实现KVO是否有必要。比如,一个对象,当另一个对象的特定属性改变的时候,需要被通知到。

例如,PersonObject希望能够觉察到BankObject对象的accountBalance属性的任何变化。

 

(2)那么PersonObject必须发送一个“addObserver:forKeyPath:options:context:”消息,注册成为BankObject的accountBalance属性的观察者。

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

(说明:“addObserver:forKeyPath:options:context:”方法在指定对象实例之间建立了一个连接。注意,这个连接不是两个类之间建立的,而是两个对象实例之间建立的。)

 

(3)为了能够响应消息,观察者必须实现“observeValueForKeyPath:ofObject:change:context:”方法。这个方法实现如何响应变化的消息。在这个方法里面我们可以跟自己的情况,去实现应对被观察对象属性变动的相应逻辑。

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

 

(4)假如遵循KVO规则的话,当被观察的属性改变的话,方法“observeValueForKeyPath:ofObject:change:context:”会自动被调用。

4KVO总结:

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

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

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


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 NSNotificationCenter

- (NSString *)name;

- (id)object;

- (NSDictionary *)userInfo;

作用:NSNotificationCenter是专门供程序中不同类间的消息通信而设置的.

注册通知:即要在什么地方接受消息

               [[NSNotificationCenter defaultCenter]  addObserver:self selector:@selector(mytest:) name:@" mytest" object:nil]

      参数介绍:

          addObserver: 观察者,即在什么地方接收通知;

        selector: 收到通知后调用何种方法;

        name: 通知的名字,也是通知的唯一标示,编译器就通过这个找到通知的。

发送通知:调用观察者处的方法。

           [[NSNotificationCenter defaultCenter] postNotificationName:@"mytest" object:searchFriendArray];

          参数:

         postNotificationName:通知的名字,也是通知的唯一标示,编译器就通过这个找到通知的。

                 object:传递的参数

注册方法的写法:

- (void) mytest:(NSNotification*) notification

{

   id obj = [notification object];//获取到传递的对象

4.移除通知:removeObserver:和removeObserver:name:object:

其中,removeObserver:是删除通知中心保存的调度表一个观察者的所有入口,而removeObserver:name:object:是删除匹配了通知中心保存的调度表中观察者的一个入口。

这个比较简单,直接调用该方法就行。例如:

[[NSNotificationCenter defaultCenter] removeObserver:observer name:nil object:self];

注意参数notificationObserver为要删除的观察者,一定不能置为nil。

PS:这里简单说一下通知中心保存的调度表。通知中心的调度表是给一些观察者指定的一些通知集。一个通知集是通知中心发出的通知的子集。每个表的入口包含:

通知观察者(必须要的)、通知名称、通知的发送者。

下图表示通知集中指定的通知的调用表入口的四种类型:

下图表示四种观察者的调度表


最后,提醒一下观察者收到通知的顺序是没有定义的。同时通知发出和观察的对象有可能是一样的。通知中心同步转发通知给观察者,就是说 postNotification: 方法直到接收并处理完通知才返回值。要想异步的发送通知,可以使用NSNotificationQueue。在多线程编程中,通知一般是在一个发出通知的那个线程中转发,但也可能是不在同一个线程中转发通知。



这篇关于KVC、KVO、NSNotification的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/428597

相关文章

iOS--KVO的实现原理与具体应用

iOS--KVO的实现原理与具体应用 本文分为2个部分:概念与应用。 概念部分旨在剖析KVO这一设计模式的实现原理,应用部分通过创建的项目,以说明KVO技术在iOS开发中所带来的作用; 如果是作为是刚接触KVO的初学者,可以在了解基本原理后粗略看几遍底层实现原理,再认真阅读第二部分的应用内容“学会”怎么去使用KVO,往后再慢慢深入了解KVO这一“黑魔法”技术的实现原理。 【本次开发环境:

NSNotification、delegate和KVO的…

1.效率肯定是delegate比nsnotification高。 2. delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值, 也就是delegate方法的结果。比如-windowShouldClose:,需要关心返回的是yes还是no。所以delegate方法往往包含 should这个很传神的词。也就是好比你做我的delegat

轻量级KVO ——》 KVO 管理 observeValueForKeyPath

【转】http://joeyio.com/2013/10/21/lightweight_kvo/ 在这篇文章中,我会实现一个自己用的简单KVO类,我认为KVO非常棒,然而对于我大部分的使用场景来说,有这两个问题: 1. 我不喜欢在observeValueForKeyPath:ofObject:change:context:方法里通过keyPath值来做调度,当Observ

KVO详解及底层实现

什么是KVO?? KVO就是NSKeyValueObserving,请看官方文档的解释: 大概翻译如下: 一种非正式协议,通知其他对象的指定属性发生了改变。 简单理解就是,可以监听一个对象的某个属性是否发生改变。 那么问题来了,什么是非正式协议??有正式协议吗?? 麻蛋,本来想找官方文档的,找了半天没找到。从Stackoverflow找到了答案,貌似原来官方文档的链接失效了

(译)KVO的内部实现

转自:http://www.cocoachina.com/applenews/devnews/2014/0107/7667.html 09年的一篇文章,比较深入地阐述了KVO的内部实现。 KVO是实现Cocoa Bindings的基础,它提供了一种方法,当某个属性改变时,相应的objects会被通知到。在其他语言中,这种观察者模式通常需要单独实现,而在Objective-C中,通

iOS OC底层面试题(KVO (Key-value observing))

KVO (Key-value observing) KVO是观察者模式的另一实现。 使用了isa混写(isa-swizzling)来实现KVO 使用setter方法改变值KVO会生效,使用setValue:forKey即KVC改变值KVO也会生效,因为KVC会去调用setter方法 - (void)setValue:(id)value{[self willChangeValueForKey

iOS OC底层面试题(KVC(Key-value coding)

KVC(Key-value coding) -(id)valueForKey:(NSString *)key;-(void)setValue:(id)value forKey:(NSString *)key; KVC就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时

KVC模式讲解和Block语法

KVC键值编码,使用完整实例: #import <Foundation/Foundation.h> @interface Course : NSObject {     NSString* courseName; } - (NSString*)description; @end   #import "Course.h" @implementation Course - (NS

iphone新手上路: KVC模式和iPhone基本控件的使用

MVC是一种设计模式,所谓设计模式就是解决某一特定问题的方案。 MVC是解决具有UI的应用系统的成熟解决方案,在Cocoa应用系统中严格按照该模式实现。 M-Model(模型)是应用系统中与视图对于部分的数据。 V-View(视图)是应用系统中用户看到并与之交互的界面。 C-Controller(控制器)是应用系统中起到控制器作用,接受用户事件,显示数据等,与视图进行交互等。 采用MVC

KVC设计模式讲解

在Objective-c语言中,可以用@property和@synthesize来创建实例变量的属性,因此对象访问的时候可以直接使用点语法。         但是,如果不声明属性,如何访问到对象的实例变量呢?KVC就解决了这一问题。         KVC  全称Key-Value-Coding,也就是键值编码。先看下面一个例子:  @interface  Student