KVO

          KVO在OC中是实现键值(key-value-observing)观察的方式,在设计模式中是典型的观察者模式, 当观察者将被观察者的某个属性设置为观察的对象时,若被观察的该属性值发生变化时,就会触发观察者对象所实现的KVO接口方法,从而达到通知观察者的目的。

        简单来说KVO可以通过监听key,来获得value的变化,用来在对象之间监听状态变化。KVO的定义都是对NSObject的扩展来实现的,Objective-C中有个显式的NSKeyValueObserving类别名,所以对于所有继承了NSObject的类型,都能使用KVO。

         KVO的实现是基于iOS runtime机制的isa-swizzling(指针替换),当一个对象的属性被注册成被观察对象时,会生成一个中间类继承自该类,然后将该类的isa指针指向新生成的子类,这样被观察的对象就变成了这个中间类,同时重写了被观察属性的setter方法,当新对象的属性发生变化时,则会依次通知注册的观察者对象。

自动KVO(默认方式)

a、添加观测者

-(void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(nullablevoid*)context;

b、当观测的属性值发生改变时调用的函数

-(void)observeValueForKeyPath:(nullable NSString*)keyPath ofObject:(nullable id)object change:(nullable NSDictionary*)change context:(nullablevoid*)context;

c、移除观察者

- (void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath context:(nullablevoid*)context;

        注意,如果被观察的属性没有调用Setter方法,而是通过直接访问其实例变量(_下划线方法)是不会触发回调的。

手动KVO

        KVO在属性发生改变的时候默认是自动调用的,如果需要手动的控制这个调用时机,那么在被观察的对象.m文件中调用如下方法:

+(BOOL)automaticallyNotifiesObserversForKey:(NSString*)key{

returnYES;//默认,自动模式

returnNO;//手动模式

}

同时在属性变化之前,调用:

-(void)willChangeValueForKey:(NSString*)key;

在属性变化之后,调用:

-(void)didChangeValueForKey:(NSString*)key;

        其实无论属性的值是否发生改变,是否调用Setter方法,只要调用了willChangeValueForKey:和didChangeValueForKey:就会触发回调。

依赖键KVO

如果在当前Person类中引入另外一个Dog类:

@interface Dog : NSObject

@property (copy, nonatomic) NSString *age;

@property (copy, nonatomic) NSString *name;

@end

那么此时我们怎么通过Person来观察Dog类的age属性呢?

[_p addObserver:self forKeyPath:@"dog.age" options:NSKeyValueObservingOptionNew    context:nil];

我们现在希望,只要Dog类中有属性的变化,就会通知到Person类,如果我们每一个属性都添加一遍观察者会很麻烦,这里就需要用到属性依赖。我们在Person类的.m中添加一个方法:

+(NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key

{

    NSSet *keyPath = [super keyPathsForValuesAffectingValueForKey:key];

    if([keyisEqual:@"dog"]) {

        keyPath = [[NSSetalloc]initWithObjects:@"_dog.age",@"_dog.name",nil];

    }

    returnkeyPath;

}

同时在添加观察者时,不用对dog具体的属性添加,直接对dog进行观察。

[_p addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionNew context:nil];

        设置键之间的依赖关系+(NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key;当添加一个被观察的keyPath,这个方法就会走。其大概意思是就是:用一组键的值去影响另一个键值。注意该方法一定要考虑非指定key时的情况要调用[super keyPathsForValuesAffectingValueForKey:key],不能影响其他的情况。

你可能感兴趣的:(KVO)