モデル オブジェクトのプロパティの KVO 通知用にビュー コントローラーを登録することに興味があります。
ビュー コントローラーの「メンバー」プロパティは NSManagedObject サブクラスであり、Core Data の提供されたアクセサー メソッドを ( 経由で@dynamic
) 使用します。これには、firstName、lastName、nickname、bio の 4 つのプロパティがあり、これらはすべて 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」プロパティを変更すると 3 つの通知を受け取り、firstName、lastName、またはニックネームを変更すると 4 つの通知を受け取ります。これは常に 3 つの通知が多すぎます。
私が間違っていたのは単純なことのようですが、無関係な通知の原因はわかりません。変更ディクショナリを指定すると、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 つの通知 (新しい値が null のプロパティごとに 1 つ、最後に予想される通知) を受信したために失敗します。