iOS KVO和KVC介绍
KVO和KVC都是基于对NSObject的扩展来实现的,所有继承于NSObject的子类都能使用KVO和KVC。
用来测试的model:
@interface User : NSObject
@property (assign, nonatomic) NSInteger uid;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) Float64 height;
@property (strong, nonatomic) User *subUser;
@end
KVO
KVO全称Key Value Observing。使用KVO可以监听对象的某个key或者keyPath它的value值的变化。
- key可以视为对象的属性
- keyPath是针对对象的属性也是一个对象的情况,使用"object.property"的形式来访问属性对象(object)的属性(property)
- 对象的属性修改之后马上就会同步调用观察者的observeValueForKeyPath:ofObject:change:context:方法。等该方法执行完毕之后才会返回修改的位置执行之后的逻辑。
- 在添加观察者的时候需要添加option:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew,这样在回调observeValueForKeyPath的时候就可以通过change字典:change[“new”]和change[“old”]来获取新旧值。
示例:
{
User *user = [User new];
user.name = @"an old name";
[user addObserver:self forKeyPath:NSStringFromSelector(@selector(name)) options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
NSLog(@"准备修改user.name");
user.name = @"a new name";
NSLog(@"修改user.name完成");
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"观察到user.name发生变化, old:%@, new:%@", change[@"old"], change[@"new"]);
NSLog(@"user.class: %@", [NSString stringWithUTF8String: class_getName([object class])]);
}
运行结果:
2019-07-19 14:22:35.595521+0800 MakeStrong[4975:90955] 准备修改user.name
2019-07-19 14:22:35.595731+0800 MakeStrong[4975:90955] 观察到user.name发生变化, old:an old name, new:a new name
2019-07-19 14:22:35.595817+0800 MakeStrong[4975:90955] user.class: User
2019-07-19 14:22:35.595920+0800 MakeStrong[4975:90955] 修改user.name完成
上述代码我们使用了NSStringFromSelector(@selector(name))
来 获取属性名,是为了避免硬编码。
KVC
KVC全称Key Value Coding。使用KVC可以不需要调用getter跟setter就可以获取和修改对象的属性值。KVC同样也是有key和keyPath的概念。
修改value的方法:
获取value的方法:
示例:
//KVC
User *user = [User new];
user.subUser = [User new]; //首先需要实例化subUser,否则下面的setValue会无效
[user setValue:@"momingqi" forKeyPath:@"subUser.name"]; //修改user.subUser.name属性
NSString *subUserName = [user valueForKeyPath:@"subUser.name"];
NSLog(@"%@", subUserName);
KVC中还有两个特殊的方法:
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
- 这个方法需要NSObject的子类重写,否则会抛出异常NSUndefinedKeyException。
- (id)valueForUndefinedKey:(NSString *)key;