iOS底层笔记--KVO本质

172 阅读2分钟

前言

本文属笔记性质,是对kirito_song冰凌天两位文章学习和转载

文章具体地址:
MJiOS底层笔记--KVO本质
小码哥iOS学习笔记第四天: KVO的本质

NSKVONotifying_Person

KVO时,将被监听的对象isa指针动态修改成新类NSKVONotifying_Person

在对一个(Person)instance对象使用KVO进行监听时,系统利用RuntimeAPI动态生成一个(Person的)子类,并且让(Person)instance对象的isa指向这个全新的子类

NSKVONotifying_Person内部

  • isa

指向NSKVONotifying_Person内部元类,提供方法实现

  • superClass、class

为了掩盖NSKVONotifying_Person的存在,修改了这两个方法。使其结果与Person类返回的相同。

Class cls = object_getClass(self.person1);
Class spcls =class_getSuperclass(cls);
NSLog(@"object_getClass==%@",cls);
NSLog(@"class==%@",[self.person1 class]);
NSLog(@"class_getSuperclass==%@",spcls);
NSLog(@"superclass==%@",[self.person1 superclass]);

//打印
object_getClass==NSKVONotifying_MJPerson
class==MJPerson
class_getSuperclass==MJPerson
superclass==NSObject
  • dealloc

做一些收尾工作

  • isKVOA

鉴定是否使用KVO

_NSSetXXXValueAndNotify

被监听对象属性的set方法IMP指针所指方法

Foundation下的一个C语言函数,当调用被监听对象属性的set方法时,实际上将会调用这个C语言方法。 其内部将会调用一系列方法修改成员变量并且触发监听

- (void)setAge:(int)age
{
    _NSSetIntValueAndNotify();
}

// 伪代码
void _NSSetIntValueAndNotify()
{
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

willChangeValueForKey && didChangeValueForKey

  1. 触发监听的方法。可以手动调用以主动触发监听

只有被监听的属性被修改,才会调用这个方法
未被监听的属性修改不会触发

  1. 两个方法需要配对使用

只调用didChangeValueForKey不会触发监听

KVO触发条件

    1. 通过set方法为属性赋值
    1. 直接修改成员变量不会触发监听
    1. KVC赋值是可以触发KVO的:
      KVC内部实现了通知逻辑(willChangeValueForKey&&didChangeValueForKey)。即使没有实现set方法,也能被通知。

手动调用KVO

KVO在属性发生改变时的调用是自动的,如果想要手动控制这个调用时机,或想自己实现KVO属性的调用,则可以通过KVO提供的方法进行调用。

- (void)setBalance:(double)theBalance {
    if (theBalance != _balance) {
        [self willChangeValueForKey:@"balance"];
        _balance = theBalance;
        [self didChangeValueForKey:@"balance"];
    }
}

可以看到调用KVO主要依靠两个方法,在属性发生改变之前调用willChangeValueForKey:方法,在发生改变之后调用didChangeValueForKey:方法。

如果想控制当前对象的自动调用过程,也就是由上面两个方法发起的KVO调用,则可以重写下面方法。方法返回YES则表示可以调用,如果返回NO则表示不可以调用。

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"balance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

参考资料
www.jianshu.com/p/cf079e543…