iOS 之路iOS技术收藏ios basic

细说KVO & KVC & NSNotifica

2015-11-11  本文已影响4665人  dullgrass

<p style = "text-indent:2em;font-size = 20px;">在iOS开发过程中,我们经常会听到或者用到KVO,KVC,NSNotificationCenter等,但是很多时候,我们可能没有那么了解,下面让我们来详细了解下他们的概念、用法以及他们之间的关系吧~</p>

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

欢迎访问作者个人博客www.dullgrass.com,更多好的文章与您分享

下面就进入正题吧~

什么是KVC?

1. KVC(键值编码)的概念:
<p style = "text-indent:2em;font-size = 20px;">苹果的官方文档描述: KVC(Key-Value-Coding)是一种通过字符串描述而不是通过调用访问方法或者直接使用实例变量的非直接的访问对象属性的机制。</p>

<p style = "text-indent:2em;font-size = 20px;">KVC 是观察者模式在Objective-C中的实现之一,它以分类(非正式协议)的形式被定义在NSObject中,从协议的角度看,是定义了一套让开发者遵守的规范和使用方法。</p>

2. KVC的用途
<p style = "text-indent:2em;font-size = 20px;">在Cocoa的MVC框架中,KVC是ViewControler和Model沟通的桥梁。</p>

<p style = "text-indent:2em;font-size = 20px;">KVC的基本方法都定义在了NSKeyValueCoding的非正式协议中,如下图所示:(NSObject默认实现了该协议,也就是说OC中几乎所有的对象都支持KVC操作)。</p>

@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;

<p style = "text-indent:2em;font-size = 20px;">KVC可以用来访问对象的属性、一对一的关系对象、一对多的关系对象</p>

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

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

  valueForKeyPath:返回跟接收者相关的键路径的值,对于子系列中任何不遵循KVC的对象,都会收到一个valueForUndefineKey:消息。
  1. 访问集合对象: 可以是可变集合和不可变集合,可变集合与KVO结合,可以实现批量更新(需传入多个对象)的功能。

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

<p style = "text-indent:2em;font-size = 20px;">KVC可以设置属性的值</p>
setValue:forKey用来将接收者中相关key的值设置成指定的值。在这个方法的实现中,会将NSValue的值转换成普通的数值然后赋值给属性。
<p style = "text-indent:2em;font-size = 20px;">KVV(Key-Value-Validate)键值验证</p>

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

什么是KVO?

  1. 观察者模式的基本思想:
    <p style = "text-indent:2em;font-size = 20px;">观察者模式主要是,通过一个对象来管理所有依赖于它的观察者对象,并在它自身的状态改变时主动通知观察者对象。 目标对象通知观察者通常是通过调用各观察对象所提供的接口方法来实现的.观察者模式比较完美的将目标对象与观察者对象解耦.</p>

  2. KVO 的应用场景:
    <p style = "text-indent:2em;font-size = 20px;">当一个对象的特定属性改变的时候,需要被通知一个或者多个对象的时候。</p>

  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;

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

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

<p style = "text-indent:2em;font-size = 20px;">当一个观察者需要观察多个对象的同一个keyPath时,可以通过设置context来区分不同的通知。</p>

  1. 属性依赖
    <p style = "text-indent:2em;font-size = 20px;">简单点说,就是通过观察一个key的值,来观察多个属性的变化,需要对象实现以下几个方法。</p>

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

KVC与KVO的关系

<p style = "text-indent:2em;font-size = 20px;">KVO是基于KVC实现的,只有我们调用KVC去访问key值的时候KVO才会起作用。</p>

KVC Collection Operators(KVC集合操作符)

  1. KVC 集合操作符的概念:
    <p style = "text-indent:2em;font-size = 20px;">KVC集合操作符允许在valueForKeyPath:方法中使用key path符号“@”,在一个集合中执行方法。结果可以被返回或者链接。</p>

  2. KVC 集合操作符的类型(根据返回值的类型来分):

  1. 简单的集合操作符

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

  1. 对象操作符

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
)

  1. 数组和集合操作符

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. 通知中心的概念:
    <p style = "text-indent:2em;font-size = 20px;">通知中心是 Foundation 框架的一个子系统,也是一个观察者模式,它向应用程序中注册为某个事件观察者的所有对象广播消息(即通知),可以在不同类之间通信的时候使用。</p>
  1. 组成通知中心的两个类:
  1. 通知中心的使用流程:

[[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. 相同点:
  1. 不同点:

NSNotificationCenter与Delegate的比较

<p style = "text-indent:2em;font-size = 20px;">通知比Deleagte可以实现更大跨度的通信机制,可以为两个无引用关系的两个对象进行通信,即事件发出者和响应者可以没有任何耦合关系。</p>

上一篇下一篇

猜你喜欢

热点阅读