Objective-C中的KVO
admin
2024-02-03 17:52:51

Objective-C中的KVO可以用来监听某个属性的变化,当属性发生变化的时候,会通知到观察者。使用KVO,需要在观察者类使用-addObserver:forKeyPath:options:context:接口注册监听,当监听对象有变化的时候,会通过-observeValueForKeyPath:ofObject:change:context:方法将对象的值传递给观察者。

KVO原理

一个Object被观察的时候,系统会动态创建Object的子类,以NSKVONotifying开头,在子类中重写属性的set方法,在重写的set方法中调用-willChangeValueForKey:和-didChangeValueForKey:方法,如果一个Object没有观察者的时候,对应的动态子类会被删除。

新建一个CustomClass类,这个类有属性string,字符串类型

@interface CustomClass : NSObject@property(nonatomic, strong) NSString *string;@end

在另外一个类中添加KVO监听,并且重写observeValueForKeyPath:ofObject:change:context:方法

CustomClass *obj = [[CustomClass alloc] init];
//NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld是枚举,可以同时监听旧值和新值
[obj addObserver:self forKeyPath:@"string" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
obj.string = @"str";
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{if ([keyPath isEqualToString:@"string"]) {NSString *res = change[NSKeyValueChangeNewKey];NSLog(@"%@", res);}
}

在obj.string = @“str”;这行前加断点,断点断住的时候,在lldb调试器中执行 po object_getClass(obj),输出是NSKVONotifying_CustomClass,执行po [obj class],输出是CustomClass。

obj被监听后,不仅重新了set方法,还重写了class方法,是为了能输出正确的class类型。

添加移除监听的方法

[obj removeObserver:self forKeyPath:@"string"];

这行代码执行后,再次输入po object_getClass(obj)和po [obj class],输出的都是CustomClass,此时KVO子类已经被释放了。

KVO可监听的对象

从KVO的原理可以看出,它的实现基于重写set方法,所以对于成员变量无法通过KVO监听,因为成员变量没有set方法。

KVO可以监听@property开头的属性变量,因为属性变量有set方法。

对于.h中声明readonly的对象,如果.m文件中声明为readwrite,这种属性变量也可以监听。

如果某个属性不想被监听,可以通过重写+automaticallyNotifiesObserversForKey:方法,在方法中返回NO即可。

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
{if ([key isEqualToString:@"string"]) {return NO;} else {return YES;}
}

相关内容

热门资讯

山水皆有情!丽江两山一江的千年... 去过丽江、走过虎跳峡的人,大概率都听过哈巴雪山和金沙江的传说。很多人站在峡谷之下,望着奔腾不息的金沙...
活力中国调研行丨“殷”你而来 ... 9月12日,游客在殷墟博物馆“甲骨文展厅”内参观。位于河南省安阳市的殷墟博物馆新馆是首个全景式展现商...
浦江之夜赴美好相逢,第37届上... 9月12日晚,黄浦江畔灯火璀璨,第37届上海旅游节大巡游在外滩中山东一路上演。不少观众早早便来到外滩...
美丽中国丨秋韵紫鹊界 梯田入画... 这是9月11日拍摄的紫鹊界梯田(无人机照片)。 金秋九月,湖南省娄底市新化县紫鹊界梯田稻谷渐次成熟。...
中国之巅奏响《共同的节日》,千... 千吨阻尼器,“迎世赛、游上海旅游节”。9月13日,由上海市文化和旅游局指导推出上海旅游·会客│巅峰之...