Key-Value Coding (KVC)
KVC 是一种访问对象属性的机制,它允许通过字符串键(key)间接访问属性,而不是直接调用存取方法或直接访问实例变量。KVC 为对象提供了一种通用的方法来访问和修改其属性。KVC 的常用方法有:
-
valueForKey:
:通过键名获取属性值。 -
setValue:forKey:
:通过键名设置属性值。
KVC 的实现原理:
-
查找顺序:
- 首先查找与键名同名的
getter
方法(如key
或isKey
)。 - 如果没有找到,查找
key
或_key
命名的实例变量。 - 如果仍未找到,则调用
valueForUndefinedKey:
方法,默认实现会抛出异常。
- 首先查找与键名同名的
-
设置值:
- 首先查找与键名同名的
setter
方法(如setKey:
)。 - 如果没有找到,查找
key
或_key
命名的实例变量,然后直接访问它。 - 如果仍未找到,则调用
setValue:forUndefinedKey:
方法,默认实现会抛出异常。
- 首先查找与键名同名的
Key-Value Observing (KVO)
KVO 是一种观察某个对象属性变化的机制。当对象的属性发生变化时,KVO 会自动通知观察者。KVO 通过注册观察者来监听属性的变化。
KVO 的实现原理:
-
动态子类:
- 当一个对象的某个属性被观察时,KVO 动态创建该对象的子类,并重写属性的
setter
方法。 - 在重写的
setter
方法中,先调用willChangeValueForKey:
,然后调用原始的setter
方法,最后调用didChangeValueForKey:
。
- 当一个对象的某个属性被观察时,KVO 动态创建该对象的子类,并重写属性的
-
通知机制:
-
willChangeValueForKey:
和didChangeValueForKey:
会在属性值变化前后发送通知。 - 观察者通过实现
observeValueForKeyPath:ofObject:change:context:
方法来接收变化通知。
-
KVO 的注意事项:
- KVO 只能观察符合 KVC 的属性。
- 手动触发 KVO 通知时,需要在属性值变化前后分别调用
willChangeValueForKey:
和didChangeValueForKey:
。
以下是一个 KVO 和 KVC 的示例代码:
// Person.h
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end
// Person.m
@implementation Person
@end
// main.m
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
// KVC 访问属性
[person setValue:@"Alice" forKey:@"name"];
NSString *name = [person valueForKey:@"name"];
NSLog(@"Name: %@", name); // 输出: Name: Alice
// 注册 KVO 观察者
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
// 修改属性触发 KVO
person.name = @"Bob";
// 移除 KVO 观察者
[person removeObserver:self forKeyPath:@"name"];
}
return 0;
}
// 实现 KVO 回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"name"]) {
NSLog(@"Name changed to: %@", change[NSKeyValueChangeNewKey]);
}
}