高质量博客
sunnyxx:《objc kvo简单探索》
南峰子的技术博客:NSKeyValueObserving(KVO)
Facebook开源的KVOController
Facebook开源的KVOController源码解读
青少年一定要读的KVO指南
KVO的原理
简而言之就是:
1、当对象有观察者时,系统runtime动态创建对象的子类、重写class方法返回父类(隐藏自己),对象的isa指向这个新类;
2、对象被观察的属性,新类重写setter方法,执行setter前后通知属性的所有观察者;
3、当一个属性没有观察者时候,删除重写的setter方法;
4、当对象没有观察者时候(移除监听),删除动态创建的子类;
记录一下不常用的用法
NSKeyValueObservingOptions
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
// 提供属性的新值
NSKeyValueObservingOptionNew = 0x01,
// 提供属性的旧值
NSKeyValueObservingOptionOld = 0x02,
// 如果指定,则在添加观察者的时候立即发送一个通知给观察者
NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04,
// 如果指定,则在每次修改属性时,会在修改通知被发送之前预先发送一条通知给观察者
// 这与-willChangeValueForKey:被触发的时间是相对应的
NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08
};
NSKeyValueObservingOptionInitial
self.name = @"1";
NSLog(@"监听前");
[self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionInitial |NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
NSLog(@"监听后,修改前");
self.name = @"2";
NSLog(@"修改后");
/* NSLog
监听前
keyPath=name change={
kind = 1;
new = 1;
}
监听后,修改前
keyPath=name change={
kind = 1;
new = 2;
old = 1;
}
修改后
*/
NSKeyValueObservingOptionPrior
self.name = @"1";
NSLog(@"监听前");
[self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionPrior |NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
NSLog(@"监听后,修改前");
self.name = @"2";
NSLog(@"修改后");
/* NSLog
监听前
监听后,修改前
keyPath=name change={
kind = 1;
notificationIsPrior = 1;
old = 1;
}
keyPath=name change={
kind = 1;
new = 2;
old = 1;
}
修改后
*/
依赖设置
@interface ViewController ()
@property (nonatomic, strong) NSString *fullName;
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@end
@implementation ViewController
// fullName依赖firstName和lastName
- (NSString *)fullName {
return [NSString stringWithFormat:@"%@ %@",_firstName,_lastName];
}
+ (NSSet *)keyPathsForValuesAffectingFullName {
return [NSSet setWithObjects:@"firstName", @"lastName", nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserver:self forKeyPath:@"fullName" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
self.firstName = @"lao";
self.lastName = @"wang";
/*NSLog
keyPath=fullName change={
kind = 1;
new = "lao (null)";
old = "(null) (null)";
}
keyPath=fullName change={
kind = 1;
new = "lao wang";
old = "lao (null)";
}
*/
}
集合属性 如:NSMutableArray、NSMutableSet、NSMutableOrderedSet
[self addObserver:self forKeyPath:@"nameArr" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
self.nameArr = [[NSMutableArray alloc] init]; // 触发KVO
[self.nameArr addObject:@"1"]; // 这么操作不触发KVO
NSMutableArray *arr = [self mutableArrayValueForKey:@"nameArr"];
// 使用mutableArrayValueForKey获得集合,操纵addObject
// 下面都触发KVO
[arr addObject:@"2"];
[arr replaceObjectAtIndex:0 withObject:@"3"];
[arr removeAllObjects];