KVO(key value observer) 键值观察者,是一种观察者模式。
KVO只能观察属性不能观察成员变量。
注册观察者:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
observer: 观察者。为nil就没有任何意义。
keyPath: 被观察的属性
options: 观察的选项,其中有:
NSKeyValueObservingOptionNew //返回 修改的值
NSKeyValueObservingOptionOld //返回 修改前的值
NSKeyValueObservingOptionInitial //注册和改变时候发通知 初始值
NSKeyValueObservingOptionPrior //改变之前发一次 之后发一次 新旧值都会发送通知
context:观察者上下文(万能指针可以用来区分KVO)
回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context;
keyPath:观察的属性
object: 观察者
change: 返回的自动 可用上面添加观察者所填写的的options做key,获取对应的值
context: 观察者上下文(万能指针可以用来区分KVO)
移除
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context;
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
object: 观察者
keyPath:观察的属性
context: 观察者上下文(万能指针可以用来区分KVO)
根据使用情况来移除;一般在dealloc中移除。
示例:
#import "KVOViewController.h"
@interface KVOClass : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation KVOClass
@end
@interface KVOViewController ()
@property (nonatomic, strong) KVOClass *kvoClass;
@end
@implementation KVOViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.kvoClass = [[KVOClass alloc]init];
self.kvoClass.name = @"name";
[self.kvoClass addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"change: %@",change);
}
-(void)dealloc{
//下面两个方法任性其一
[self.kvoClass removeObserver:self forKeyPath:@"name"];
[self.kvoClass removeObserver:self forKeyPath:@"name" context:nil];
}
@end
禁止属性被自动观察
下面两种方法都可以可以使属性不被上面的方法监听,可以在被观察的对象中添加下面方法:
//方法1 默认return YES return NO禁止所有的属性被观察
+(BOOL)automaticallyNotifiesObserversOfName{
return NO;
}
//方法2 根据key进行观察控制 return NO禁止属性名为key的属性被观察
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"key"]) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
区别就是 方法2的优先级比方法1高
@implementation KVOClass
// 默认return YES return NO 该类下所有属性不能被观察监听
+(BOOL)automaticallyNotifiesObserversOfName{
return NO;
}
// return NO 属性名为name的属性不能被观察监听
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"name"]) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
@end
手动调用
在禁止自动观察的情况下,可以使用手动调用。
#import "KVOViewController.h"
@interface KVOClass : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation KVOClass
// 默认return YES return NO 该类下所有属性不能被观察监听
+(BOOL)automaticallyNotifiesObserversOfName{
return NO;
}
// return NO 属性名为name的属性不能被观察监听
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"name"]) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
@end
@interface KVOViewController ()
@property (nonatomic, strong) KVOClass *kvoClass;
@end
@implementation KVOViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.kvoClass = [[KVOClass alloc]init];
self.kvoClass.name = @"name";
[self.kvoClass addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld context:nil];
[self.kvoClass willChangeValueForKey:@"name"];
self.kvoClass.name = @"newName";
[self.kvoClass didChangeValueForKey:@"name"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"change: %@",change);
}
-(void)dealloc{
//下面两个方法任性其一
[self.kvoClass removeObserver:self forKeyPath:@"name"];
[self.kvoClass removeObserver:self forKeyPath:@"name" context:nil];
}
@end
其中
//修改之前
- (void)willChangeValueForKey:(NSString *)key;
//修改之后
- (void)didChangeValueForKey:(NSString *)key;
需要成对出现,只调用一个是没有观察者回调的。
个人知识点记录