面试题答案
一键面试注册KVO的步骤
- 准备被观察对象:确保被观察对象的属性是遵循KVO机制的。通常,属性需要通过
@property
声明,并使用@synthesize
自动合成存取方法(在现代的Objective-C中,@synthesize
通常可省略)。例如:
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end
- 注册观察者:在观察者对象中,调用被观察对象的
addObserver:forKeyPath:options:context:
方法进行注册。例如:
Person *person = [[Person alloc] init];
[self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
addObserver:
参数为观察者对象,通常是self
,表示当前对象进行观察。forKeyPath:
指定要观察的属性的键路径,这里是name
。options:
指定观察选项,如NSKeyValueObservingOptionNew
表示观察新值,NSKeyValueObservingOptionOld
表示观察旧值,也可以两者组合。context:
是一个指针,用于传递上下文信息,通常设为nil
。
实现回调方法
观察者需要实现observeValueForKeyPath:ofObject:change:context:
方法,当被观察对象的属性值发生变化时,系统会调用该方法。例如:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"name"]) {
NSString *newName = change[NSKeyValueChangeNewKey];
NSLog(@"The name has changed to %@", newName);
}
}
keyPath
:发生变化的属性的键路径。object
:被观察的对象。change
:包含属性变化信息的字典,如NSKeyValueChangeNewKey
对应新值,NSKeyValueChangeOldKey
对应旧值。context
:注册时传递的上下文指针。
KVO的基本原理
-
动态生成子类:当一个对象注册为另一个对象属性的观察者时,运行时系统会动态创建被观察对象类的一个子类。例如,对于
Person
类,会创建一个类似NSKVONotifying_Person
的子类。 -
方法重写:这个动态子类重写了被观察属性的存取方法。例如,对于
name
属性,会重写setName:
方法。当调用setName:
方法时,除了设置新值外,还会通知所有注册的观察者属性发生了变化。 -
通知机制:系统通过
observeValueForKeyPath:ofObject:change:context:
方法将属性变化的信息传递给观察者。观察者根据这些信息进行相应的处理。 -
内存管理:当不再需要观察时,观察者需要调用被观察对象的
removeObserver:forKeyPath:
方法取消观察,以避免内存泄漏。例如:
[person removeObserver:self forKeyPath:@"name"];