iOS开发知识

浅谈KVO用法以及底层实现

2019-08-07  本文已影响0人  太阳骑士索拉尔

关于我的仓库

前言

使用以及注意点

三个方法

addObserver:forKeyPath:options:context:

observeValueForKeyPath:ofObject:change:context:

removeObserver:forKeyPath:

实操见真章

8FA8B5E2-B8A7-4306-81FE-136642B74C1C
- (void)clickButton:(UIButton *)sender {
    NSLog(@"CLICK");
    if (sender.tag == 101) {
        NSLog(@"CLICK1");
        [self addObserver:self.kvoPerson forKeyPath:@"testStr" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
    } else if (sender.tag == 102) {
        NSLog(@"CLICK2");
        [self removeObserver:self.kvoPerson forKeyPath:@"testStr"];
    } else if (sender.tag == 103) {
        NSLog(@"CLICK3");
        self.testStr = @"QSTSD";
    } else {
        _kvoPerson = nil;
    }
}

俺也整一个【自己实现KVO】

//第一步:我们需要认识下面这个方法,如果想要手动调用或自己实现KVO需要重写该方法该方法返回YES表示可以调用,返回NO则表示不可以调用。
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"name"]) {
        automatic = NO;//对该key禁用系统自动通知,若要直接禁用该类的KVO则直接返回NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

//第二步:我们需要重写setter方法
- (void)setName:(NSString *)name {
    if (name != _name) {
        [self willChangeValueForKey:@"name"];
        _name = name;
        [self didChangeValueForKey:@"name"];
    }
}

实现原理

测试代码

NSKeyValueObservingOptions option = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
    
NSLog(@"person1添加KVO监听对象之前-类对象 -%@", object_getClass(self.person1));
NSLog(@"person1添加KVO监听之前-方法实现 -%p", [self.person1 methodForSelector:@selector(setAge:)]);
NSLog(@"person1添加KVO监听之前-元类对象 -%@", object_getClass(object_getClass(self.person1)));
    
[self.person1 addObserver:self forKeyPath:@"age" options:option context:@"age chage"];
    
NSLog(@"person1添加KVO监听对象之后-类对象 -%@", object_getClass(self.person1));
NSLog(@"person1添加KVO监听之后-方法实现 -%p", [self.person1 methodForSelector:@selector(setAge:)]);
NSLog(@"person1添加KVO监听之后-元类对象 -%@", object_getClass(object_getClass(self.person1)));

//打印结果
KVO-test[1214:513029] person1添加KVO监听对象之前-类对象 -Person
KVO-test[1214:513029] person1添加KVO监听之前-方法实现 -0x100411470
KVO-test[1214:513029] person1添加KVO监听之前-元类对象 -Person
  
KVO-test[1214:513029] person1添加KVO监听对象之后-类对象 -NSKVONotifying_Person
KVO-test[1214:513029] person1添加KVO监听之后-方法实现 -0x10076c844
KVO-test[1214:513029] person1添加KVO监听之后-元类对象 -NSKVONotifying_Person
  
//通过地址查找方法
(lldb) p (IMP)0x10f24b470
(IMP) $0 = 0x000000010f24b470 (KVO-test`-[Person setAge:] at Person.h:15)
(lldb) p (IMP)0x10f5a6844
(IMP) $1 = 0x000000010f5a6844 (Foundation`_NSSetLongLongValueAndNotify)

NSKVONotifying_Person

img img

setter方法内部实现

几个注意点

全流程图

687474703a2f2f7777322e73696e61696d672e636e2f6c617267652f303036744e6337396c793167357132676a316834736a333165363075307161382e6a7067
上一篇 下一篇

猜你喜欢

热点阅读