最近写代码写的有点飘,回过头来看ios的基础发现我对KVO机制的用法和传参居然不太熟悉。
KVO是Key Value Observe的缩写,中文是键值观察。这是一个典型的观察者模式,观察者在键值改变时会得到通知。
KVO的使用也很简单,就是简单的3步。
1.注册需要观察的对象的属性addObserver:forKeyPath:options:context:
2.实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用
3.取消注册观察removeObserver:forKeyPath:context:
注册观察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
//----------使用及参数讲解----------
//被观察者对象调用此方法注册监听
//observer 观察者对象
//keyPath 被观察者对象的属性名
//options 有四种事件属性,通常使用 NSKeyValueObservingOptionNew观察值的改变
//context 扩展属性,传递一个指针(变量指针、对象指针、函数、block)
监听事件
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
//----------使用及参数讲解----------
//在观察者类中实现此方法
//keyPath 被观察者属性名
//object 被观察者对象本身
//change 被观察者前后改变的属性值
//context 扩展参数
KVO的使用其实超级简单,这里就不过多说明了。主要讲一下context参数的使用。
在注册方法中传入context参数,当监听方法被回调时得到的context参数与注册方法中传入的context参数是同一个对象。而context参数是任意的指针参数,也就是说满足传入值要求的参数必须是个指针,那么相应的监听方法中就要以指针形式去接收数据。
下面讲解4种类型指针的传入与对应的解析:1、基本数据类型 2、对象类型 3、函数 4、block块函数
1、基本数据类型
//注册观察者
self.person= [[Person alloc]init];
self.person.age = 3;
self.param = 5;
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:¶m];
//改变属性即触发监听
self.person.age = 20;
//监听事件
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{
NSLog(@"%d",*(int*)context);
}
//结果为5
2、对象类型
//注册观察者
_dict = [NSMutableDictionary dictionary];
_dict[@"cheshi"]= @"测试";
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:(__bridge void * _Nullable)(_dict)];
//改变属性即触发监听
self.person.age = 20;
//监听事件
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{
id res = (__bridge id)(context);
if ([res isKindOfClass:[NSMutableDictionary class]]) {
NSLog(@"%@",res);
}
}
//结果为:{cheshi = "\U6d4b\U8bd5";}
3、函数
void test1(){
NSLog(@"test1函数被触发了");
};
//注册观察者
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:test1];
//改变属性即触发监听
self.person.age = 20;
//监听事件
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{
void (*test)(void) = context;
test();
}
//执行结果:test1函数被触发了
4、block块函数
//声明block
typedef void (^CheshiBlock)(void);
CheshiBlock cheb = ^(void) {
NSLog(@"block触发");
};
//注册观察者
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:(__bridge void * _Nullable)(cheb)];
//改变属性即触发监听
self.person.age = 20;
//监听事件
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{
CheshiBlock bbb = (__bridge CheshiBlock)(context);
bbb();
}
//执行结果:block触发
最后注意一点,注册了观察者事件,一定要在合适的地方移除事件。
转载请注明出处@@
网友评论