先来定义一个类,要被我们监听的类
- YSPerson.h 文件
#import <Foundation/Foundation.h>
@interface YSPerson : NSObject
@property (assign, nonatomic) int age;
@end
- YSPerson.m文件
@implementation YSPerson
{
int _age;
}
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return _age;
}
@end
在控制器中监听YSPerson 实例对象的 age
- (void)viewDidLoad {
[super viewDidLoad];
self.person1 = [[YSPerson alloc] init];
self.person1.age = 1;
NSLog(@"person1添加KVO监听之前 - %@",
object_getClass(self.person1));
NSLog(@"person1添加KVO监听之前 - %p",
[self.person1 methodForSelector:@selector(setAge:)]);
// 给person1对象添加KVO监听
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.person1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
NSLog(@"person1添加KVO监听之后 - %@",
object_getClass(self.person1));
NSLog(@"person1添加KVO监听之后 - %p ",
[self.person1 methodForSelector:@selector(setAge:)]);
/*
通过上面的打印输出,可以证明,监听前后的实例对象的类型和
setAge的方法地址都是不一样的,验证了我们的猜想
*/
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// self.person1.age = 21;
// NSKVONotifying_YSPerson是使用Runtime动态创建的一个类,是YSPerson的子类
// self.person1.isa == NSKVONotifying_YSPerson
[self.person1 setAge:21];
}
- (void)dealloc {
[self.person1 removeObserver:self forKeyPath:@"age"];
}
// 当监听对象的属性值发生改变时,就会调用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
}
-
当我们点击屏幕的时候,给self.person1的age赋值 21时候,我们就能监听到值的改变
-
实现原理是利用Runtime来完成
-
当我们监听了YSPerson的属性的时候,系统会在Runtime阶段为我们创建一个NSKVONotifying_YSPerson ,这个类继承自YSPerson
-
在NSKVONotifying_YSPerson的实现中插入了以下代码
@implementation NSKVONotifying_YSPerson
- (void)setAge:(int)age
{
_NSSetIntValueAndNotify();
}
// 伪代码
void _NSSetIntValueAndNotify()
{
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
}
- (void)didChangeValueForKey:(NSString *)key
{
// 通知监听器,某某属性值发生了改变
[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
@end
- 并将NSKVONotifying_YSPerson的 class 方法,所以在我们调用[self.person1 class] 方法的时候返回的还是YSPerson
网友评论