欢迎大家关注我的公众号,我会定期分享一些我在项目中遇到问题的解决办法和一些iOS实用的技巧,现阶段主要是整理出一些基础的知识记录下来
文章也会同步更新到我的博客:
ppsheep.com
在Objc中有一种观察者模式,即是Key Value Observing(KVO)。利用KVO可以很容易实现视图组件和数据模型的分离。当数据模型的值改变时,会马上触发视图组件,更新视图组件。在Objc中要实现KVO,必须实现NSKeyValueObServing协议,所幸的是NSObject已经实现该协议,也就是说,几乎所有的Objc对象都可以使用KVO。
在OC中,KVO的使用步骤一般是:
- 被监听者通过 addObserver:forKeyPath:options:context: 方法,添加监听
- 监听者重写 observeValueForKeyPath:ofObject:change:context: 方法,实现监听
- 被监听者移除监听
简单的实现一下,首先,我需要一个监听对象,所以创建一个Entity
// Entity.h
#import
@interface Entity : NSObject
@property (nonatomic, copy) NSString *name;
/**
因为另外两个属性没有暴露出来 我们只能通过方法来改变
*/
- (void)changeName1:(NSString *)name1;
- (void)changeName2:(NSString *)name2;
@end复制代码
// Entity.m
@interface Entity()
@property (nonatomic, copy) NSString *name1;
@end
@implementation Entity
{
@private
NSString *_name2;
}
- (instancetype)init
{
self = [super init];
if (self) {
_name = @"name";
_name1 = @"name1";
_name2 = @"name2";
}
return self;
}
-(void)changeName1:(NSString *)name1{
_name1 = name1;
}
-(void)changeName2:(NSString *)name2{
_name2 = name2;
}
@end复制代码
这里 我们建了三个属性,name,name1,name2, 每个name属性都是不一样的定义,这也是我们日常coding中,最常见的三种属性定义方式。
待会我们试着对这三个属性都进行监听,看一下效果如何?
被监听者,已经创建完成了,我们现在需要一个监听者
self.model = [[Entity alloc] init];
UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 100,200, 30)];
btn1.tag = 100001;
[btn1 addTarget:self action:@selector(changeName:) forControlEvents:UIControlEventTouchUpInside];
[btn1 setTitle:@"改变name" forState:UIControlStateNormal];
[self.model addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
UIButton *btn2 = [[UIButton alloc] initWithFrame:CGRectMake(100, 200,200, 30)];
btn2.tag = 100002;
[btn2 addTarget:self action:@selector(changeName:) forControlEvents:UIControlEventTouchUpInside];
[btn2 setTitle:@"改变值name1" forState:UIControlStateNormal];
[self.model addObserver:self forKeyPath:@"name1" options:NSKeyValueObservingOptionNew context:nil];
UIButton *btn3 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300,200, 30)];
btn3.tag = 100003;
[btn3 addTarget:self action:@selector(changeName:) forControlEvents:UIControlEventTouchUpInside];
[btn3 setTitle:@"改变值name2" forState:UIControlStateNormal];
[self.model addObserver:self forKeyPath:@"name2" options:NSKeyValueObservingOptionNew context:nil];
[self.view addSubview:btn1];
[self.view addSubview:btn2];
[self.view addSubview:btn3];复制代码
三个按钮分别对应三个属性,点击每个按钮 触发不同的KVO
改变model的属性
- (void)changeName: (UIButton *)btn{
switch (btn.tag) {
case 100001:
self.model.name = @"change";
break;
case 100002:
[self.model changeName1:@"change"];
break;
case 100003:
[self.model changeName2:@"changge"];
break;
default:
break;
}
}复制代码
当然一定不要忘记了,重写observeValueForKeyPath方法:
//KVO监听回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSLog(@"%@", keyPath);
}复制代码
打印出当前的keypath
一定不要忘记移除监听
-(void)dealloc{
[self.model removeObserver:self forKeyPath:@"name"];
[self.model removeObserver:self forKeyPath:@"name1"];
[self.model removeObserver:self forKeyPath:@"name2"];
}复制代码
经过试验 我们发现 只有点击第一个按钮,即name属性对应的按钮,才会触发监听。
从这一点,我们可以发现,只有在.h中暴露出来的属性,才能被KVO监听到,.m中的属性,是不能够被监听到。
一个简单的KVO
demo放在: