一直对KVO 和KVC都是停留在 只是知道的情况,从来没有尝试这在项目中使用,最近准备总结一下,在项目里面简单的使用一下
1、什么是KVO?
KVO其实就是Key-Value-Observer,也就是键值观察者,是基于KVC机制实现的另一种模式。也许有不少同学用过SVPullToRefresh或者MJRefresh刷新组件,都使用了KVO来实现。
看了一下感觉kvo有些地方和通知有一些相同的地方,因此在有时候可以使用KVO来代替通知,
举个栗子,
在当前VC里面,当另外一个dataModel类中的某个属性变化时,我需要即时的得到dataModel变化的信息,并且得到所变化的值,这个时候使用键值观察者模式就非常方便了
下面为dataModel类:
#import <Foundation/Foundation.h>
#import "KVOClass.h"
@interface Student : NSObject
@property(nonatomic) NSString *studentName;
@property (nonatomic) float grade;
@property(nonatomic)KVOClass *kvoClass;
@end
设置一秒之后改变 数据模型中的 属性 studentName的值,
-(void)changename{
self.studentName =@"学生的名字改为+++老王了";
[selfsetValue:@"学生的名字改为+++老王了"forKey:@"studentName"];
}
在VC里面,dataModel类的对象添加一个观察者来检测
这样只要model类属性发生变化,这边既可以得到通知,实现对应的逻辑功能即可,一般做数据的更新比较方便。。。
#import "KVOClass.h"
#import "Student.h"
#import "Teacher.h"
@implementation KVOClass
- (instancetype)init
{
self = [super init];
if (self) {
self.student= [[Student alloc]init];
self.teacher = [[Teacher alloc]init];
//某一对象本身添加 本类对象 为观察者
[self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"name"];
//某一对象添加本类对象为观察者
[self.student addObserver:self forKeyPath:@"studentName" options:0|1context:nil];
//某一对象添加其他类对象为观察者
[self.student addObserver:self.teacher forKeyPath:@"studentName" options:0|1context:nil];
}
return self;
}
实现收到通知的方法;哪个类 添加观察者 ,哪个类就负责实现这个方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if (context == @"name") {
NSLog(@"%@",self.name);
}else if ([keyPath isEqualToString:@"studentName"]){//回调方法必须处理,否则会crash掉!!!!!!!
NSLog(@"本类对象++++%@",self.student.studentName);
}else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
下面是在其他类Teacher中处理回调函数的情况
/****
change 通知回调的参数,包含所检测对象的值的变化 change[@"new"]即可取到
注意!!! change[@"new"]取到的值全是对象数据类型,没有基本数据类型的(如果是 int float等,得到的是NSNumber类型)
同样的 kvc的时候赋值的时候也要是对象类型,基本类型数据要转成对象类型的
*****/
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"studentName"]) {
NSLog(@"老师貌似收到了学生信息改变的通知了,+++%@",change[@"new"]);
}else if ([keyPath isEqualToString:@"grade"]){
NSLog(@"老师貌似收到了学生信息改变的通知了,+++%@",change[@"new"]);
}
}
移除观察者, 哪个类 添加观察者 ,哪个类就负责移除观察者
-(void) dealloc
{
[self removeObserver:self forKeyPath:@"name"];
[self.student removeObserver:self forKeyPath:@"studentName"];
[self.student removeObserver:self.teacher forKeyPath:@"studentName"];
[self.student removeObserver:self.teacher forKeyPath:@"grade"];
}
总结一下:
//总结 1、谁成为观察者,谁就要实现收到通知的回调方法,可以在当前类(添加观察者的类),也可以在观察者的类中去实现,
// 2、添加观察者与移除观察者是成对出现的,一定要记得移除,原则是在那个类添加就在那个类移除观察者。否则会crash!!!
// 3、某一对象可以添加当前类的对象为观察者,也可以添加其他类的对象为观察者,
。 KVC和字典转模型
http://www.2cto.com/kf/201507/415647.html
http://www.bkjia.com/IOSjc/989396.html
//****************** 使用 KVC 自动字典转模型 ******************//
NSDictionary *dic = @{@"name":@"cheng",@"nick":@"laocheng",@"addr":@"henan",@"phone":@(10086),@"test":@"false"};
Student *student = [[Student alloc]init];
[student setValuesForKeysWithDictionary:dic]; // 使用 KVC 自动字典转模型,实体类只有声明一下属性,此方法可以自动把字典的key
//和value 分别赋给 实体
// /如果kvc转模型的时候 传的字典里面的key如果没有对应属性的key时,会自动调用此方法
// -(void)setValue:(id)value forUndefinedKey:(NSString *)key{
NSLog(@"phone : %@",student.phone);
//****************** 使用 KVC 自动模型转字典 ******************//
NSDictionary *dict = [student dictionaryWithValuesForKeys:@[@"name",@"nick",@"addr",@"phone"]];
NSLog(@"dict : %@",dict);
数据模型
@interface Student : NSObject
@property(nonatomic)NSString *name;
@property(nonatomic)NSString *nick;
@property(nonatomic)NSString *addr;
@property(nonatomic)NSNumber *phone;
@property(nonatomic)NSString *testProperty;
@end