iOS KVO和KVC原理详解

KVO

KVO的全称是Key-Value Observing,俗称“键值观察者”,可以用于监听某个对象属性值的改变。

  • 当给对象添加KVO时,OC会通过runtime的API动态生成一个继承于该类对象的派生类(NSKVONotifying_对象名),并且使这个interface对象的isa指针指向于这个派生类。
  • 当修改interface对象被监听的属性时,调用派生类重写的set方法。
    [] set方法中调用Foundation框架中的_NSSet(属性类型)ValueAndNotify函数。在_NSSet(属性类型)ValueAndNotify函数中调用方法顺序如下:
    --1. 调用willChangeValueForKey:方法。
    --2. 调用父类的set方法。
    --3. 调用didChangeValueForKey:方法。该方法内部会调用observer的监听方法(observeValueForKeyPath:ofObject:change:context:)。

补充:

该动态生成的派生类会重写这几个方法:set方法、class方法、dealloc方法、-isKVOA方法。

代码:

  1. 创建被观察者对象并添加属性:
@interface Person : NSObject

@property(nonatomic, copy)NSString *name;

@end
  1. 初始化被观察者:
Person *per = [[Person alloc] init];
  1. 给被观察者添加observe:
 /**
   *per:被观察者
   *observer:观察者
   *forKeyPath:被监听的属性
   *options:有四个值
          1、NSKeyValueObservingOptionNew 把更改之前的值提供给监听方法
          2、NSKeyValueObservingOptionOld 把更改之后的值提供给监听方法
          3、NSKeyValueObservingOptionInitial 把初始化的值提供给监听方法,一旦 册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
          4、NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
   *context:上下文,可以带一些参数,任何类型都可以
   */
[per addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"test"];
  1. 在观察者中添加监听方法:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"new:%@  old:%@", change[@"new"], change[@"old"]);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

问题:

  • 如何手动触发KVO?
    手动调用willChangeValueForKey:和didChangeValueForKey:。
  • 直接修改成员变量会触发KVO嘛?
    不会触发,因为KVO的本质是触发set方法,成员变量没有set方法。
  • 通过KVC修改属性会触发KVO嘛?
    会触发,因为KVO的本质是触发set方法。

KVC

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

  • (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
  • (void)setValue:(id)value forKey:(NSString *)key;
  • (id)valueForKeyPath:(NSString *)keyPath;
  • (id)valueForKey:(NSString *)key;

setValue:(id)value forKey:(NSString *)key的工作原理:

setValue:forKey:的原理

valueForKey:(NSString *)key的工作原理:

valueForKey:的工作原理

你可能感兴趣的:(iOS KVO和KVC原理详解)