#import "ViewController.h"
#import "FQPeople.h"
@interface ViewController ()
@property(nonatomic,strong) FQPeople *people;
@property(nonatomic,strong) FQPeople *people1;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.people = [FQPeople new];
self.people1 = [FQPeople new];
self.people1.age = 20;
self.people.age = 20;
[self.people addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%@",@"这里被执行了");
self.people.age = 21;
[self.people1 setAge:22];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString: @"age"] && object == self.people) {
NSLog(@"%@",change);
}
}
- (void)dealloc{
[self removeObserver:self forKeyPath:@"age"];
}
1.1、引入
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.people.age = 21;
[self.people1 setAge:22];
}
这两个方法都调用了People类的setAge方法。为什么people监听会被调用,people1不会呢?
setter方法是一样的,那就是people对象有不一样的地方, 接着往下看
1.2、isa的指向
不使用kvo (没有注册监听的时候)poeple 的isa指针指向的原来的类,即:WQPeople
使用kvo
在runtime创建了一个MJPerson的子类新类NSKVONotifying_MJPerson,并把poeple对象的isa指针指向 NSKVONotifying_MJPerson的类对象,
self.p1 = [[People alloc] init];
self.p2 = [[People alloc] init];
[self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
NSLog(@"%@",object_getClass(self.p1));//NSKVONotifying_People
NSLog(@"%@",object_getClass(object_getClass(self.p1)));//People
NSLog(@"%@",object_getClass(object_getClass(object_getClass(self.p1))));//NSObject
NSLog(@"%@",object_getClass(self.p2));//People
NSLog(@"%@",object_getClass(object_getClass(self.p2)));//People
NSLog(@"%@",object_getClass(object_getClass(object_getClass(self.p2))));//People
1.3、方法的调用流程
没有使用kvo:
self.p1 = [[People alloc] init];
self.p2 = [[People alloc] init];
[self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
p2,没有使用kvo,没有产生新的类,直接使用p2的isa指针找到p2的类对象,底层是objc_sendMsg() 这个流程访问原来的People中的setAge
使用了kvo runtime产生了新的类,
先p1的isa 找到People的类对象 找到NSKVONotifying_FQPeople 的setAge 在调用这个setAge时,调用的是fundation框架的 _NSSetIntValueAndNotify()
_这个_NSSetXXXValueAndNotify() 执行
-
willChangeValueForKey
-
父类原来的setter进行真正的赋值
-
didChangeValueForKey;
这里面会触发observe监听器的observeValueForKeyPath:ofObject:change方法。
那么setAge 和NSSetXXXValueAndNotify怎么关联的呢?
执行setAge时它的方法指针(IMP)直接指向了NSSetXXXValueAndNotify
[self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
///获取imp
[self.p1 methodForSelector:@selector(setAge:)];
大概实现是