我有兴趣在模型对象的属性中注册我的视图控制器以用于KVO通知。KVO +托管对象 - 接收太多通知
视图控制器的“member”属性是一个NSManagedObject子类,它使用Core Data提供的访问器方法(通过@dynamic
)。它有四个属性:firstName,lastName,nickname和bio,它们都是NSString。
下面是KVO的注册和注销:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.member addObserver:self
forKeyPath:@"firstName"
options:NSKeyValueObservingOptionNew
context:kFHMemberDetailContext];
[self.member addObserver:self
forKeyPath:@"lastName"
options:NSKeyValueObservingOptionNew
context:kMemberDetailContext];
[self.member addObserver:self
forKeyPath:@"nickname"
options:NSKeyValueObservingOptionNew
context:kMemberDetailContext];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.member removeObserver:self forKeyPath:@"firstName" context:kMemberDetailContext];
[self.member removeObserver:self forKeyPath:@"lastName" context:kMemberDetailContext];
[self.member removeObserver:self forKeyPath:@"nickname" context:kMemberDetailContext];
}
回调方法的实现
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context != kFHMemberDetailContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
self.kvoCount++;
if ([keyPath isEqualToString:@"firstName"]) {
NSLog(@"firstName KVO'd");
}
else if ([keyPath isEqualToString:@"lastName"]) {
NSLog(@"lastName KVO'd");
}
else if ([keyPath isEqualToString:@"nickname"]) {
NSLog(@"nickname KVO'd");
}
}
当我驱动从一个单元测试该代码时,收到三个通知,当我修改“bio”属性以及修改firstName,lastName或昵称时的四个通知。这通常是三个太多的通知!
这似乎是简单的,我做错了,但我无法弄清楚是什么导致无关的通知。如果我po更改字典,NSKeyValueChangeKindKey总是NSKeyValueChangeSetting,但对于不需要的通知NSKeyValueChangeNewKey是NULL。
测试驱动该位的代码:
- (void)setUp
{
NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:@[[NSBundle mainBundle]]];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
[psc addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:nil
error:NULL];
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator:psc];
member = [NSEntityDescription insertNewObjectForEntityForName:@"Member" inManagedObjectContext:managedObjectContext];
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
memberDetailVC = [sb instantiateViewControllerWithIdentifier:kFHMemberDetailTableViewControllerIdentifier];
[memberDetailVC setMember:member];
}
- (void)tearDown
{
[memberDetailVC viewWillDisappear:NO];
}
- (void)testChangesToMemberFirstNamePropertyCausesKVO
{
[memberDetailVC viewWillAppear:NO];
[member setFirstName:@"Unit Test"];
STAssertTrue(memberDetailVC.kvoCount, (NSInteger)1, @"View controller should have received a single KVO notification");
}
就像我说,这个失败已经接收4个通知(一个用于与空的新的值的每个属性,然后最终预期的通知) 。
上下文变量是复制+粘贴错误;对于那个很抱歉!我已经添加了测试代码,看看是否可以揭示我做错的任何事情。我当然可以按照你的建议解决这个问题,但我想知道为什么它首先发生,看看我是否做了不正确的事情! – edelaney05 2013-02-14 13:20:15
另外,注册通知的更好的钩子在'viewDidAppear'中。此外,请确保在您的单元测试中没有任何其他代码不在您的代码中(例如循环)或从不同测试中重复更改。 – Mundi 2013-02-14 13:26:17