高质量博客
sunnyxx:《objc kvo简单探索》
南峰子的技术博客:NSKeyValueObserving(KVO)
Facebook开源的KVOController
青少年一定要读的KVO指南
KVO的原理
简而言之就是:
1、当一个object有观察者时,动态创建这个object的类的子类、重写 class隐藏自己,返回原来类的class
2、对于每个被观察的property,重写其set方法
3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
4、当一个property没有观察者时,删除重写的方法
5、当没有observer观察任何一个property时,删除动态创建的子类
记录一下不常用的用法
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];
网友评论