1)KVC概念
Key-Value Coding,即键值编码。它是一种不通过存取方法,而通过属性名称字符串间接访问属性的机制。
1. 赋值方法:
- (void)setValue:(id)value forKey:(NSString *)key;
2.获取属性的方法: - (id)valueForKey:(NSString *)key;
3.通过path获取多层级的属性,比如:student.name
- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
(在属性相当于由两部分组成:key相当于属性名,value相当于赋的值。从而达到间接赋值的作用)
2)KVO概念
Key-Value Obersver,即键值观察。它是观察者模式的一种衍生。基本思想是,对目标对象的某属性添加观察,当该属性发生变化时,会自动的通知观察者。这里所谓的通知是触发观察者对象实现的KVO的接口方法。
** KVO是解决model和view同步的好法子。**
另外,KVO的优点是当被观察的属性值改变时是会自动发送通知的,这比通知中心需要post通知来说,简单了许多。
KVO的原理:
重新的setter方法里到底干了什么,而使其就有了通知机制呢?其实只是在setter方法里,给属性赋值的前后分别调用了两个方法
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;
而- (void)didChangeValueForKey:(NSString *)key;
会调用
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
这就是KVO实现的基本原理了!
KVO方法实现需要四步:
1.首先给目标对象的属性添加观察:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
3.接收通知,需要注意各个参数的含义:
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
举一个例子:
#import "ViewController.h"
#import "Student.h"
@interface ViewController ()
{
Student *_student;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_student = [[Student alloc] init];
_student.stuName = @"oldName_hu";
// 1.给student对象的添加观察者,观察其stuName属性
[_student addObserver:self forKeyPath:@"stuName" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
// 此时,stuName发生了变化
_student.stuName = @"newName_wang";
}
// stuName发生变化后,观察者(self)立马得到通知。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
// 最好判断目标对象object和属性路径keyPath
if(object == _student && [keyPath isEqualToString:@"stuName"])
{
NSLog(@"----old:%@----new:%@",change[@"old"],change[@"new"]);
}else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
// 移除观察者
[_student removeObserver:self forKeyPath:@"stuName"];
}
@end
补充:下面是自己模仿的例子打印信息
2018-03-08 21:55:41.531000+0800 Test[913:69576] 现在:
乔布斯
设备信息:
macBook ,8000
Iphone ,5000
Ipid ,2000
Person *psn=[[Person alloc]init];
psn.name=@"乔布斯";
2018-03-08 21:55:41.531121+0800 Test[913:69576] KVC不同对象变化
Person *pe1=[[Person alloc]init];
pe1.name=@"大胖";
NSLog(@"---KVC不同对象变化------%@", psn.name);
2018-03-08 21:55:41.531202+0800 Test[913:69576] ---KVC不同对象变化------乔布斯
2018-03-08 21:55:41.531286+0800 Test[913:69576] KVC相同对象变化
[psn setValue:@"牛魔王" forKey:@"name"];
NSLog(@"---KVC相同对象变化---%@", psn.name);
2018-03-08 22:08:28.068447+0800 Test[953:82848] ---KVC相同对象变化---牛魔王
NSLog(@"通过路径获取属性值:%@", [psn valueForKey:@"name"] );
2018-03-08 22:08:28.068531+0800 Test[953:82848] 通过路径获取属性值:牛魔王
2018-03-08 21:55:41.531616+0800 Test[913:69576] KVO机制
playTools=@"牛蛋儿";
[psn setValue:@"草蛋儿" forKey:@"playTools"];
2018-03-08 21:55:41.532100+0800 Test[913:69576]
------New:草蛋儿
-------Old:牛蛋儿
发现:
1).在KVC的setValue间接赋值中,创建不同的对象setValue赋值修改的属性也不同;所以要求对像相统一;
2).在观察者方法中的Object(对象),keypath(属性名),change[new] change[old] 代表最新赋值和之前的赋值;
3).KVO的优势:1. 我们可以通过实现观察者方法来获取判断想要的对象;
2. 属性值改变几次就会促发实现的方法几次;