KVC传值/获取值
kvc用于多层对象之间的赋值传值。
1.key
示例:
KVCViewController 逻辑处理对象
@property (nonatomic) Student *student;
Student 对象:
Student.h文件
{
NSString *_zhuangBei;
}
@property (nonatomic,copy) NSString *name;
@property (nonatomic) NSString *id;
Student.m文件
//私有变量
{
NSString *_daTui;
}
Computer对象:
Computer.h文件
{
float _weight;
}
@property (nonatomic,copy) NSString *name;
@property (nonatomic) float price;
@property (nonatomic,copy) NSString *producePlace;
代码:
//self.student->_zhuangBei
[self.student setValue:@"手机" forKey:@"zhuangBei"];
//_zhuangBei也可以
NSLog(@"%@",[self.student valueForKey:@"zhuangBei"]);
//私有的照样可以赋值和获取
[self.student setValue:@"长腿" forKey:@"daTui"];
NSLog(@"%@",[self.student valueForKey:@"daTui"]);
2.keypath
示例代码如下:
[self.student setValue:@3 forKeyPath:@"computer.weight"];
NSLog(@"***%@",[self.student valueForKeyPath:@"computer.weight"]);
[self setValue:@100 forKeyPath:@"student.computer.weight"];
NSLog(@"***%@",[self valueForKeyPath:@"student.computer.weight"]);
KVO属性观察者
注册观察者,是为了在观察值改变的时候及时进行相关处理。
// KVO Key-Value Observser
// 观察者模式,是一种设计模式
// 我们让当前控制器对象观察学生对象student的blood的变化
// 当学生对象blood一旦发生变化,当前控制器对象知道这么一个变化并做相应处理
// 观察者:当前视图控制器对象
// 被观察者:_student
如果没有注册观察者,而移除观察者,会crash
kvo 实现需要三步:
1.第一步 是注册观察
2.第二步 是实现观察方法
3.第三步 移除注册
//1. 注册观察者,让self(当前视图控制器对象)临听student
```
- (void)regist {
// self.student: 被观察者
// 第一个参数:观察者,谁是观察者,这里写成了self, 即当前对象
// 第二个参数:观察student什么
// 第三个参数:选项,当student指定的keyPath发生变化时会把哪些值组装起来,以待回调给方法 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
// 第四个参数:附加信息
[self.student addObserver:self forKeyPath:@"blood" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
// self观察student的computer的price
[self.student addObserver:self forKeyPath:@"computer.price" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:NULL];
}
//改变student属性值,触发监听
- (void)buttonClick:(id)sender {
int value = arc4random()%100;
// self.student.blood = value; // 通过点语法,实际上是通过set方法,可以触发kvo
// [self.student setValue:@(value) forKey:@"blood"]; // @(value)->[NSNumber numberWithInt:value] 通过kvc的方式也能触发kvo
// 如果是对student的成员直接赋值,不通点set方法和kvc赋值方式给blood赋值,不会触发kvo
// [self.student updateBlood:value]; // 在这个方法内部,直接:_blood = 100 这样不会触发kvo
// NSLog(@"%f", self.student.blood);
self.student.computer.price = value;
}
2.实现观察方法
代码如下:
// 当student的blood发生变化时,当前对象就会检测到,调方法:
// 第一个参数:观察的student的哪个属性的变化(可以是更深层的)
// 第二个参数:观察的哪个对象 -- student
// 第三个参数:观察到的值的变化,这些变化会放在字典change里面,我们可以通过它取到比如变化前的值和变化后的值
// 第四个参数:NULL 附加信息
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([object isKindOfClass:[Student class]]) {
NSLog(@"是的,监听到学生对象发生了变化");
}
NSLog(@"keyPath: %@", keyPath);
if ([keyPath isEqualToString:@"blood"]) {
NSLog(@"学生对象的blood发生了变化");
}
NSNumber *newValue = change[NSKeyValueChangeNewKey];
NSNumber *oldVlaue = change[NSKeyValueChangeOldKey];
NSLog(@"变化前: %f 变化后:%f", [oldVlaue floatValue], [newValue floatValue]);
}
3.移除观察者
// 学生对象被销毁了,但是仍然在监听(观察者没有移除注册,没有移除观察)
- (void)dealloc {
// 当学生消失的时候,观察者对象没理由,也不能再去观察学生对象,所以移除观察
[_student removeObserver:self forKeyPath:@"blood"];
[_student removeObserver:self forKeyPath:@"computer.price"];
}
对数组进行kvo 注册观察者
[self addObserver:self forKeyPath:@"data" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil];
//这种添加方式不会观察
// [self.data addObject:@"data1"];
//通过这种方式添加才会被观察
[[self mutableArrayValueForKeyPath:@"data"] addObject:@"data2"];