iOS-KVO

前言设计

KVO键值观察,咱们再熟悉不过了。可是大部分人对它的关注点可能都在对观察某一个keyPath,会动态建立一个继承该类的带前缀NSKVONotifying_原类名的子类,而且在子类中重写该key的setter方法这一逻辑。今天咱们来看一些可能平时不太注意的地方,而且讨论一下KVO键值观察为何要建立子类来实现。code

 

触发通知方式;server

(1)自动通知,这种应该是比较常见的,缘由在于NSObject类实现了NSKeyValueCoding协议,所以只要是继承了NSObject类的对象经过KVC进行操做就能够自动的通知到观察者。对象

(2)手动通知,这就须要让你的类重写+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key或者是+ (BOOL)automaticallyNotifiesObserversOf<key>方法,对于想要手动触发通知的,能够根据keyPath返回NO,而其对于其余位置的keyPath,要返回父类的这个方法。例如属性observingStr;继承

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

+ (BOOL)automaticallyNotifiesObserversOfObservingStr
{
    return NO;
}

 

手动触发;开发

(1)要实现手动通知,你须要在值改变前调用 willChangeValueForKey: 方法,在值改变后调用 didChangeValueForKey: 方法。你能够在发送通知前检查值是否改变,若是没有改变就不发送通知。关键在于willChangeValueForKey:以及didChangeValueForKey:这两个方法,自动通知应该就是在子类重写的setter中封装好触发通知的逻辑。get

(2)其实手动触发通知有一个细节的地方,不知道有没有人注意到,就是当你设置某个键值须要手动通知时,系统并无去动态建立带前缀NSKVONotifying_原类名,你能够经过rumtime的object_getClass(self),去验证self的isa是否指向新类,答案是没有。io

 

KVO键值观察为何要建立子类来实现?class

(1)上文也说了触发键值观察的关键方法willChangeValueForKey:和didChangeValueForKey:,咱们作个假设,假设苹果KVO机制并无经过建立子类实现,而是在当前类实现。那么会存在一个问题,就是开发者重写该属性的setter方法,而且并无去执行willChangeValueForKey:和didChangeValueForKey:两个方法,就不会触发通知观察者。object

(2)有可能跟类设计的单一责任原则有关,子类自负责封装触发通知逻辑,其余的一律无论(例如获取旧值以及赋值新值都会执行父类的方法)。例如;

- (void)setObservingStr:(NSString *)observingStr
{
    [self willChangeValueForKey:@"observingStr"];
    NSLog(@"%@", NSStringFromClass(object_getClass(self)));
    //_observingStr = observingStr;
    //[self didChangeValueForKey:@"observingStr"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"observingStr"]) {
        NSLog(@"newStr -- %@", change[NSKeyValueChangeNewKey]);
        
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

因为重写的setter方法没有赋值新值,输出newStr -- <null>;这也说明子类重写的setter方法取值和赋值是经过父类的setter方法。

 

总结

本文所讲的内容只是KVO的一部分,用于记录平时研究一些技术的心得,了解更多的内容能够查看这篇文章或者是上网查询更多内容。

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息