iOS原理(二)----KVO,KVC

iOS原理(二)----KVO,KVC

KVO

KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变.下面是一个简单实用KVO的例子:

@interface Animal : NSObject

@property (nonatomic,assign) int age;

@end

@implementation Animal

@end


- (void)viewDidLoad {
    [super viewDidLoad];
    
     self.ani = [[Animal alloc] init];
    self.ani.age = 10;
    [self.ani addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
    

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    self.ani.age = 20;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"%@---%@---%@",keyPath,object,change);
}

通过断点发现添加KVO后,对象的isa指针变为NSKVONotifying_Animal,

Snip20181109_16.png

setAge实际调用为:NSSetIntValueAndNotify

Snip20181109_17.png

大概实现为:

  • 调用willChangeValueForKey.
  • 调用原来的setter实现.
  • 调用didChangeValueForKey.

didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法.

KVO动态生成的类,还会重写class,dealloc,_isKVOA等.调用class方法,会得到原来的类对象,对外封装实现细节.

所以KVO的本质为:利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类,当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数,然后依次调用willChangeValueForKey,父类原来的setter和didChangeValueForKey(内部会触发监听器(Oberser)的监听方法( observeValueForKeyPath:ofObject:change:context:)).

当对象值没有改变时,我们任然要触发KVO时,我们可以手动触发KVO:手动调用willChangeValueForKey:和didChangeValueForKey.直接修改成员变量的值不会触发KVO.

KVC

KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性
.

setValue:forKey:的原理:

  • 按照setKey:、_setKey:顺序查找方法,如果找到方法,传递参数,调用方法.
  • 如果没有找到方法,查看accessInstanceVariablesDirectly方法的返回值.
  • 如果返回值为NO,调用setValue:forUndefinedKey:并抛出异常NSUnknownKeyException.
  • 如果返回值为YES,按照_key、_isKey、key、isKey顺序查找成员变量,如果找到成员变量,就只直接赋值,没有调用setValue:forUndefinedKey:并抛出异常NSUnknownKeyException.

valueForKey:的原理:

  • 按照getKey、key、 isKey、_key顺序查找方法,如果找到方法,调用方法.
  • 如果没有找到方法,查看accessInstanceVariablesDirectly方法的返回值.
  • 如果返回值为NO,调用valueForUndefinedKey:并抛出异常NSUnknownKeyException.
  • 如果返回值为YES,按照_key、_isKey、key、isKey顺序查找成员变量,如果找到成员变量,就只直接赋值,没有调用valueForUndefinedKey:并抛出异常NSUnknownKeyException.

KVC会自动触发KVO.

你可能感兴趣的:(iOS原理(二)----KVO,KVC)