Objective-C 中的 "NSKeyValueChangeKindKey"
异常通常是因为使用了错误的 key path 或者监听属性的对象没有遵循 KVO(键值观察)协议。下面我将详细讲解异常的原因和解决方法,并提供两个示例:
原因
一般情况下,KVO 的使用是需要三个步骤:
- 注册观察者。
- 添加观察者。
- 实现监听方法。
如果其中任何一个步骤有误,调用观察者时就会报 "NSKeyValueChangeKindKey"
异常。
解决办法
如果出现了该异常,我们需要进行下面的操作:
- 首先检查 key path 是否被正确的监听。
- 确保你的监听对象实现了
NSObject
的class
或NSObject
的NSObject
遵循KVO
协议的方法。 - 使用正确的 key path。
- 检查使用的 key path 的值, 若要监听某一属性,该属性的值必须为对象。
- 确保观察者的添加和删除操作成对出现。
下面是两个示例:
示例 1:错误的 key path
// 关键路径中应该为 "name",而不是 "names"
[person addObserver:self forKeyPath:@"names" options:NSKeyValueObservingOptionNew context:nil];
上面的代码中,Person
对象中不存在 “names” 属性,因此调用观察者时就会报 "NSKeyValueChangeKindKey"
异常。解决方法是将关键路径修改为正确的值 “name” :
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
示例 2:监听对象没有遵循 KVO 协议
@interface Person : NSObject
@property (nonatomic, assign) NSUInteger age;
@end
@implementation Person
@end
// 注册观察者并添加观察者
[person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
// 相关方法实现
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"age"]) {
// 获取 age 属性的新值
NSUInteger newAge = [change[NSKeyValueChangeNewKey] intValue];
NSLog(@"Person's age has changed to: %ld", newAge);
}
}
上面的代码中Person
类中并没有遵循 KVO
协议,即没有实现 NSObject
的 class
或 NSObject
的 NSObject
遵循 KVO
协议的方法。因此调用观察者时就会报 "NSKeyValueChangeKindKey"
异常。解决方法是将 Person
类遵循 KVO
协议:
@interface Person : NSObject
@property (nonatomic, assign) NSUInteger age;
@end
@implementation Person
// 遵循 KVO 协议
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
return YES;
}
@end
// 注册观察者并添加观察者
[person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
// 相关方法实现
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"age"]) {
// 获取 age 属性的新值
NSUInteger newAge = [change[NSKeyValueChangeNewKey] intValue];
NSLog(@"Person's age has changed to: %ld", newAge);
}
}
上述代码中,我们使用了 +[NSObject automaticallyNotifiesObserversForKey:]
方法告诉 KVO,当 age
属性发生变化时,对象已经自动通知过观察者,观察者不用再次调用 willChangeValueForKey:
和 didChangeValueForKey:
方法通知对象的改变了,而是直接获取 age
的新值。配合此方法,就可以正确监听到 age
属性的变化了。
以上就是 Objective-C 报 “NSKeyValueChangeKindKey” 异常的原因和解决方式,希望能对你有所帮助。