iOS KVO(键值观察)

KVO(键值观察)

键值观察是 Objective-C 语言的动态语言特性,在运行时通过 KVO,允许一个对象观察另一个对象的属性,当变化发生时,观察者会得到通知。

1.注册观察者的方法

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

2.被监听值的修改执行的方法

//当key路径对应的属性值发生改变时,监听器就会回调自身的监听方法,如下
-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context

3.移除监听(这个要写,而且移除之前要判断之前的监听是否还存在,防止重复移除导致崩溃。而且谁注册,谁释放)

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

例如我想关注UIButton的title的变化。

注册观察者

[self.timeButton addObserver:self forKeyPath:@"titleLabel.text" options:NSKeyValueObservingOptionNew context:nil];

观察值变化

-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    if ([keyPath isEqualToString:@"titleLabel.text"]) {
        NSLog(@"titleLabel.text = %@",self.timeButton.titleLabel.text);
     }
}

移除观察者

//这是我自己一个判断键值观察还存在的
if ([Tool isObj:self.timeButton hasObserverKey:@"titleLabel.text"]) {
//移除观察者
    [self.timeButton removeObserver:self forKeyPath:@"titleLabel.text"];
    }

上面基本上就可以实现基本的kvo功能了!!!

拓展:

1.属性值变化是系统会调用下面这两个方法:

- (void)willChangeValueForKey:(NSString *)key
- (void)didChangeValueForKey:(NSString *)key
options几种值的模式
// 属性变化的类型,是一个NSNumber对象,包含NSKeyValueChange枚举相关的值
NSString *const NSKeyValueChangeKindKey;

// 属性的新值。当NSKeyValueChangeKindKey是 NSKeyValueChangeSetting,
// 且添加观察的方法设置了NSKeyValueObservingOptionNew时,我们能获取到属性的新值。
// 如果NSKeyValueChangeKindKey是NSKeyValueChangeInsertion或者NSKeyValueChangeReplacement,
// 且指定了NSKeyValueObservingOptionNew时,则我们能获取到一个NSArray对象,包含被插入的对象或
// 用于替换其它对象的对象。
NSString *const NSKeyValueChangeNewKey;

// 属性的旧值。当NSKeyValueChangeKindKey是 NSKeyValueChangeSetting,
// 且添加观察的方法设置了NSKeyValueObservingOptionOld时,我们能获取到属性的旧值。
// 如果NSKeyValueChangeKindKey是NSKeyValueChangeRemoval或者NSKeyValueChangeReplacement,
// 且指定了NSKeyValueObservingOptionOld时,则我们能获取到一个NSArray对象,包含被移除的对象或
// 被替换的对象。
NSString *const NSKeyValueChangeOldKey;

// 如果NSKeyValueChangeKindKey的值是NSKeyValueChangeInsertion、NSKeyValueChangeRemoval
// 或者NSKeyValueChangeReplacement,则这个key对应的值是一个NSIndexSet对象,
// 包含了被插入、移除或替换的对象的索引
NSString *const NSKeyValueChangeIndexesKey;

// 当指定了NSKeyValueObservingOptionPrior选项时,在属性被修改的通知发送前,
// 会先发送一条通知给观察者。我们可以使用NSKeyValueChangeNotificationIsPriorKey
// 来获取到通知是否是预先发送的,如果是,获取到的值总是@(YES)
NSString *const NSKeyValueChangeNotificationIsPriorKey;
//其中,NSKeyValueChangeKindKey的值取自于NSKeyValueChange,它的值是由以下枚举定义的:

enum {

    // 设置一个新值。被监听的属性可以是一个对象,也可以是一对一关系的属性或一对多关系的属性。
    NSKeyValueChangeSetting = 1,

    // 表示一个对象被插入到一对多关系的属性。
    NSKeyValueChangeInsertion = 2,

    // 表示一个对象被从一对多关系的属性中移除。
    NSKeyValueChangeRemoval = 3,

    // 表示一个对象在一对多的关系的属性中被替换
    NSKeyValueChangeReplacement = 4
};
typedef NSUInteger NSKeyValueChange;

你可能感兴趣的:(iOS KVO(键值观察))