细说KVO & KVC & NSNotificationCenter那些事

在iOS开发过程中,我们经常会听到或者用到KVO,KVC,NSNotificationCenter等,但是很多时候,我们可能没有那么了解,下面让我们来详细了解下他们的概念、用法以及他们之间的关系吧~

本篇博客共分以下几个模块来介绍:

  • 什么是KVC?
  • 什么是KVO?
  • KVC与KVO的关系
  • KVC Collection Operators
  • 什么是NSNotificationCenter?
  • NSNotificationCenter与KVO的比较
  • NSNotificationCenter与Delegate的比较

 

下面就进入正题吧~

什么是KVC?

1. KVC(键值编码)的概念:

苹果的官方文档描述: KVC(Key-Value-Coding)是一种通过字符串描述而不是通过调用访问方法或者直接使用实例变量的非直接的访问对象属性的机制。

KVC 是观察者模式在Objective-C中的实现之一,它以分类(非正式协议)的形式被定义在NSObject中,从协议的角度看,是定义了一套让开发者遵守的规范和使用方法。

2. KVC的用途

在Cocoa的MVC框架中,KVC是ViewControler和Model沟通的桥梁。

KVC的基本方法都定义在了NSKeyValueCoding的非正式协议中,如下图所示:(NSObject默认实现了该协议,也就是说OC中几乎所有的对象都支持KVC操作)。

@interface NSObject(NSKeyValueCoding)
- (nullable id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

KVC可以用来访问对象的属性、一对一的关系对象、一对多的关系对象

  1. 访问对象属性:也可以是对象的成员变量,成员变量是私有的也可以访问,属性可以是对象,也可以是数值类型和结构体,非对象类型的参数和返回值会自动封装成NSValue活着NSNumber类型。
    valueForKey:会返回跟接收者相关的key的值,如果对于指定的key没有访问器或者实例变量,则给自己发送一个valueForUndefineKey:消息,这个方法的默认实现是抛出一个NSUndefinedKeyException
  2. 通过关系访问对象:假设对象person有属性address,属性address有属性city,我们可以通过person来访问city:

    [person valueForKeyPath:@"address.city"];

    valueForKeyPath:返回跟接收者相关的键路径的值,对于子系列中任何不遵循KVC的对象,都会收到一个valueForUndefineKey:消息。

  3. 访问集合对象: 可以是可变集合和不可变集合,可变集合与KVO结合,可以实现批量更新(需传入多个对象)的功能。

    dictionaryWithValuesForKeys:会检索数组中所有跟接收者相关的key的值,返回的NSDictionary中包含了数组中所有key的值。

KVC可以设置属性的值

setValue:forKey用来将接收者中相关key的值设置成指定的值。在这个方法的实现中,会将NSValue的值转换成普通的数值然后赋值给属性。

KVV(Key-Value-Validate)键值验证

- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;

什么是KVO?

  1. 观察者模式的基本思想:

    观察者模式主要是,通过一个对象来管理所有依赖于它的观察者对象,并在它自身的状态改变时主动通知观察者对象。 目标对象通知观察者通常是通过调用各观察对象所提供的接口方法来实现的.观察者模式比较完美的将目标对象与观察者对象解耦.

  2. KVO 的应用场景:

    当一个对象的特定属性改变的时候,需要被通知一个或者多个对象的时候。

  3. KVO 的使用流程:
    • 注册与解除注册

      keyPath不可以为nil
      - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
      - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

    • 设置Value

      [target setAge:30]; //setter
      [target setValue:[NSNumber numberWithInt:30] forKey:@"age"]; //setValue:forKey

    • 处理变更通知

      观察者需要实现名为 NSKeyValueObserving 的 category 方法来处理收到的变更通知

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

    当一个观察者需要观察多个对象的同一个keyPath时,可以通过设置context来区分不同的通知。

  4. 属性依赖

    简单点说,就是通过观察一个key的值,来观察多个属性的变化,需要对象实现以下几个方法。

    + (NSSet *)keyPathsForValuesAffectingAddress
    {
    NSSet *set = [NSSet setWithObjects:@"firstName", @"lastName", nil];
    return set; //这方法使得 Key 之间能够建立依赖关系
    }
    //设置属性之间的依赖关系
    - (NSString *)address
    {
    return [NSString stringWithFormat:@"%@%@",self.province,self.street];
    }

KVC与KVO的关系

KVO是基于KVC实现的,只有我们调用KVC去访问key值的时候KVO才会起作用。

KVC Collection Operators(KVC集合操作符)

  1. KVC 集合操作符的概念:

    KVC集合操作符允许在valueForKeyPath:方法中使用key path符号“@”,在一个集合中执行方法。结果可以被返回或者链接。

  2. KVC 集合操作符的类型(根据返回值的类型来分):
    • 简单的集合操作符:返回值是NSString、NSNumber或者NSDate
    • 对象操算符:返回值是一个数组
    • 数组和集合操作符:返回值是一个数组或者集合
  3. 简单的集合操作符
    • @count:返回一个值为集合中对象总数的NSNumber对象
    • @sum: 首先把集合中的每个对象都转换为double类型,然后计算其总,最后返回一个值为这个总和的NSNumber对象
    • @avg: 首先把集合中的每个对象都转换为double类型,然后计算其平均值,最后返回一个值为这个总和的NSNumber对象
    • @max: 使用compare:方法来确定最大值。所以为了让其正常工作,集合中所有的对象都必须支持和另一个对象的比较
    • @min: 和@max一样,但是返回的是集合中的最小值。
    • 使用示例:

      products是数组,数组中存放了很多对象,每个对象都有一个price的属性。
      [products valueForKeyPath:@"@sum.price"];
      可以用self作为操作符后面的keyPath来获取一个由NSNumber组成的数组或者集合的总值。
      [@[@1,@2] valueForKey:@"@max.self"];

  4. 对象操作符
    • @distinctUnionOfObjects:获取数组中每个对象的属性的值,放到一个数组中并返回,会对数组去重。
    • @unionOfObjects: 同@distinctUnionOfObjects,但是不去重。
    • 使用示例:

      Person *lilei = [[Person alloc] init];
      lilei.name = @"LiLei";
      Person *hanMeiMei = [[Person alloc] init];
      hanMeiMei.name = @"hanMeiMei";
      NSArray *array = @[lilei, hanMeiMei];
      NSLog(@"array is %@",[array valueForKeyPath:@"@distinctUnionOfObjects.name"]);
      输出结果为:
      2015-11-10 16:08:07.977 TestPro[49746:521302] array is (
      LiLei,
      hanMeiMei
      )

  5. 数组和集合操作符
    • @distinctUnionOfArrays: 获取数组中每个数组中的每个对象的属性的值,放到一个数组中并返回,会对数组去重复。
    • @unionOfArrays:同@distinctUnionOfArrays,但是不去重。
    • @distinctUnionOfSets: 获取集合中每个集合中的每个对象的属性的值,放到一个集合中并返回。
    • 使用示例:

      Person *lilei = [[Person alloc] init];
      lilei.name = @"LiLei";
      Person *hanMeiMei = [[Person alloc] init];
      hanMeiMei.name = @"hanMeiMei";
      NSArray *array = @[lilei, hanMeiMei];
      NSLog(@"array is %@",[ @[array,array] valueForKeyPath:@"@unionOfArrays.name"]);
      输出结果为:
      2015-11-10 16:51:26.137 TestPro[50404:556930] array is (
      LiLei,
      hanMeiMei,
      LiLei,
      hanMeiMei
      )

什么是NSNotificationCenter?

  1. 通知中心的概念:

    通知中心是 Foundation 框架的一个子系统,也是一个观察者模式,它向应用程序中注册为某个事件观察者的所有对象广播消息(即通知),可以在不同类之间通信的时候使用。

    • 注意当接受到消息后,不想再收到消息了,要把observer删除remove。一般在类销毁的时候remove。
  2. 组成通知中心的两个类:
    • NSNotificationCenter:获取NSNotificationCenter的方法只有一种,即[NSNotificationCenter defaultCenter],并且NSNotificationCenter是一个单例模式,一旦创建,这个通知中心的对象会一直存在于一个应用的生命周期。
    • NSNotification: 这是消息携带的载体,通过它,可以把消息内容传递给观察者。
  3. 通知中心的使用流程:
    • 注册通知:NSNotificationCenter 注册观察者对某个事件(以字符串命名)感兴趣,及该事件触发时该执行的 Selector 或 Block.

      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationMethod:) name:@"notificationName" object:nil];
      参数注释:
      第一个参数(self):负责监听的对象
      第二个参数(@selector(notificationMethod:)):接收到通知之后,监听对象需要执行的方法。
      第三个参数(@"notificationName"):通知的名称,也是通知的唯一标示,编译器就是通过这个找到通知的。
      第四个参数(nil):最后一个参数是表示会对哪个发送者对象发出的事件作出响应,nil 时表示接受所有发送者的事件。

    • 发送通知:手动发送消息

      [[NSNotificationCenter defaultCenter] postNotificationName:@"notificationName" object:test userInfo:@{@"key":@"value"}];
      参数注释:
      第一个参数(@"notificationName"):通知的名称,这个名称必须和后面接收通知的名称一致
      第二个参数(test):可以传递的一个参数对象
      第三个参数(@{@"key":@"value"}):可以传递的,与通知相关的信息,

    • 移除通知:在观察者不再接收消息的时候,移除通知

      - (void)dealloc
      {
      //移除指定的通知,不然会造成内存泄露
      [[NSNotificationCenter defaultCenter] removeObserver:self name:@"happyValueNotification" object:nil];
      //移除所有的通知
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      }

NSNotificationCenter与KVO的比较

  1. 相同点:

    • NSNotificationCenter与KVO的实现原理都是观察者模式。用于监听操作
  2. 不同点:
    • KVO只用来监听属性值的变化,这个发送监听的操作是系统控制的,我们控制不了,我们只能控制监听操作,类似于Android中系统发送的广播。
    • 我们可以控制通知的发送监听,可以在任何地方任何时机发送一个通知。类似于Android中开发者自己发送的广播。
    • 通知的使用场景比KVO更为广泛些
    • 通知需要一个发送notification的对象,一般是notificationCenter,来通知观察者。KVO是直接通知到观察对象,并且逻辑非常清晰,实现步骤简单。
    • 总之,KVO操作没有通知灵活。但是KVO也有自己的优点,比如可以记录新旧值,通知就比较麻烦,所以在使用的时候还是具体问题具体分析,一般监听属性值的变化,最好还是用KVO。

NSNotificationCenter与Delegate的比较

通知比Deleagte可以实现更大跨度的通信机制,可以为两个无引用关系的两个对象进行通信,即事件发出者和响应者可以没有任何耦合关系。

时间: 2024-10-29 22:34:28

细说KVO & KVC & NSNotificationCenter那些事的相关文章

iOS开发——KVO/KVC&OC与Swift篇详解

Swift中使用KVC和KVO的类都必须必须继承自NSObject KVC key-value coding 是1种间接访问对象的机制 key的值就是属性名称的字符串,返回的value是任意类型,需要自己转化为需要的类型 KVC主要就是两个方法 (1)通过key设置对应的属性 (2)通过key获得对应的属性 举例 class TestForKVC:NSObject{ var hwcCSDN = "hello world" } var instance = TestForKVC() va

iOS:KVO/KVC 的概述与使用

KVO   APP开发技术QQ群:347072638 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了. 二,使用方法 系统框架已经支持KVO,所以程序员在使用的时候非常简单. 1. 注册,指定被观察者的属性, 2. 实现回调方法 3. 移除观察 三,实例: 假设一个场景,股票的价格显示在当前屏幕上,当股票价格更改的时候,实时显示更新其

Objective-C 观察者模式--KVO和NSNotificationCenter的使用

Objective-C中的KVO和NSNotificationCenter的原理是观察模式的很好实现, 下面用代码分别演示下用法 KVO的用法 1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 // Do any additional setup after loading the view, typically from a nib. 4 5 self.model = [Model new]; 6 7 //添加KVO 8 [self.model

KVO/KVC总结

KVO/KVC总结 下面是根据网上文章的总结,方便查看. 在网上看别人的文章,了解KVC.KVO,有个kvo-kvc的例子,就是改变数组的内容(插入和删除),同步改变tableview中的内容.运行了代码之后,想添加修改数组时改变tableview内容,但是一直不能调用观察函数,后来又查了点资料,原来,数组的kvc是都是有固定格式的函数名字.把改后的工程放到资源里面了.供大家下载.下面是拷贝过来的资料. 一.KVC和KVO的概念 1> KVC:NSKeyValueCoding的简称,是一种可以直

kvo&kvc

Key Value Coding Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property accssor, 如我们有个property叫做foo, 我们可以foo直接访问它,同样我们也可以用KVC来完成[Object valueForKey:@“foo”], 有同学就会问了, 这样做有什么好处呢?主要的好处就是来减少我们的代码量. 下面我们来看看几个例子,就明白了KVO的用法和好处了,假设这

【转】 iOS KVO KVC

原文: http://www.cocoachina.com/industry/20140224/7866.html Key Value Coding Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property accssor, 如我们有个property叫做foo, 我们可以foo直接访问它,同样我们也 “” 阅读器 iOSKVOKVC 转自:Regrecall blogger Key Valu

ios 之kvo&kvc的使用

转载:http://www.cnblogs.com/kenshincui/p/3871178.html 概述 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听(KVO)特性: 键值编码KVC 键值监听KVO 键值编码KVC 我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象.其实由于Obj

KVO && KVC

KVO: key-value observing 当指定的对象的属性被修改后,则对象就会接受到通知. 简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者. 使用步骤: 1.注册,指定被观察者的属性(由被观察者主动添加观察自己的观察者) 2.实现回调方法 3.移除观察 使用范例: @interface StockData : NSObject { NSString * stockName; float price; } @end @implementation Sto

IOS KVO与NSNotificationCenter简单使用

每次面试都被问到KVO或者通知.今天也自己来看了看通知. 1.NSNotificationCenter使用. 使用步骤:添加观察者.发送通知.移除观察者. 添加观察者:哪里需要接收通知,就在哪里加.例如: [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(reciveNotfi:) name:@"testNot" object:nil]; 发送通知: [[NSNotificationCent