KVC内部实现原理

字数 387阅读 55

- (void)setValue:(nullable id)value forKey:(NSString *)key

调用setValue方法会按照此步骤调用


屏幕快照 2018-11-14 下午5.18.44.png

1.添加2个set方法,调用setValue方法看有没有走那两个方法

屏幕快照 2018-11-15 下午2.17.05.png

2.验证accessInstanceVariablesDirectly 返回值改成NO,调用setValue会崩溃

+(BOOL)accessInstanceVariablesDirectly
{
    return NO;
}

3.验证访问成员变量顺序 分别注释以下四个成员变量然后打断点观察四个成员变量的值即可验证访问顺序

屏幕快照 2018-11-15 下午2.19.47.png

- (id)valueForKey:(NSString *)key

会按照如下顺序调用

屏幕快照 2018-11-14 下午5.17.45.png

验证步骤和上面类似,添加2个get方法,对四个成员变量赋值,看valueForKey取到的值是哪个值

setValue会触发KVO吗?会

1.此种方式会按照上面的流程图调用,如果监听了name属性会触发KVO,如果没有监听不会触发
[self setValue:@"ss" forKey:@"name"];
2.此种方式监听了成员变量age的KVO,也会触发KVO,如果没有监听不会触发
[self setValue:@10 forKey:@"age"];
{
    @public
    int age;
}

有些同学可能知道KVO的原理是衍生了子类重写了set方法,set方法里调用 NSSetIntValueAndNotify,但是成员变量压根没有set方法仍然会触发KVO,猜测应该是对成员变量赋值的时候

    [self willChangeValueForKey:@"name"]
     成员变量赋值
    [self didChangeValueForKey:@"name"]

注意!!!!!!!!

3.此种方式下划线开头是直接赋值_name的成员变量的值,如果没有这个成员变量会直接崩溃NSUnknownKeyException,如果监听了_name的KVO会触发KVO
[self setValue:@"ss" forKey:@"_name"];
如果下面这样带下划线开头 直接寻找此变量,如果没有这个成员变量会直接崩溃
[self valueForKey:@"_age"];
总结就是[self setValue:value forKey:@"_key"] 此形式赋值 key带有下划线开头是直接找这个成员变量,能否触发kvo取决于添加kvo时key是否和KVC用的key相等

1.属性 @property (nonatomic,copy)NSString *name;

  • 以下情况不会触发kvo
 [self addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"_name"];

或者

 [self addObserver:self forKeyPath:@"_name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"name"];
  • 以下情况会触发kvo
 [self addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"name"];

或者

 [self addObserver:self forKeyPath:@"_name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"_name"];

2.成员变量

{ NSString * _name; }

  • 以下情况不会触发kvo
 [self addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"_name"];

或者

 [self addObserver:self forKeyPath:@"_name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"name"];
  • 这种情况会触发kvo
 [self addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"name"];

或者

 [self addObserver:self forKeyPath:@"_name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"_name"];

3.成员变量名不带下划线{ NSString * name; }

  • 会崩溃的情况
[self setValue:@"sss" forKey:@"_name"];
  • 以下情况会触发kvo
 [self addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"name"];
  • 以下情况不会触发kvo
 [self addObserver:self forKeyPath:@"_name" options:(NSKeyValueObservingOptionNew)|NSKeyValueObservingOptionOld context:nil];
 [self setValue:@"sss" forKey:@"name"];