问题
I have one managed object with a one-to-many relationship to member class. When I add the observers for members, it worked. When one new member is added to the relationship, the observeValueForKeyPath will be invoked with the new object and change dictionary contains the new member object. However, observeValueForKeyPath will be triggered second time with all values nil and change dictionary new="NULL". What is the second trigger? I set a breakpoint, but not sure who made the trigger.
@interface FooObject : NSManagedObject {}
@property (nonatomic, strong) NSString *fooId;
@property (nonatomic, strong) NSSet* members;
@end
@implementation FooObject
@dynamic fooId;
@dynamic members;
- (NSMutableSet*)membersSet {
[self willAccessValueForKey:@"members"];
NSMutableSet *result = (NSMutableSet*)[self mutableSetValueForKey:@"members"];
[self didAccessValueForKey:@"members"];
return result;
}
- (void)registerObservers {
[self addObserver:self
forKeyPath:@"members"
options:NSKeyValueObservingOptionNew
context:nil];
}
- (void)unregisterObservers {
@try{
[self removeObserver:self forKeyPath:@"members"];
}@catch(id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
id valueNewSet = [change objectForKey:NSKeyValueChangeNewKey];
if (![valueNewSet isKindOfClass:[NSSet class]]) {
// not a NSSet, it contains <null> value
NSLog(@"%@", change);
NSLog(@"%@", object);
}
if ([[change objectForKey:NSKeyValueChangeKindKey] intValue] == NSKeyValueChangeInsertion) {
// insert change is valid, process the changes
}
}
@end
Log output:
{
kind = 1;
new = "<null>";
}
<FooObject: 0xfa9cc60> (entity: FooObject; id: 0xfa9be00 <x-coredata://39DB31FD-6795-4FDE-B700-819AB22E5170/SHInterest/p6> ; data: {
fooId = nil;
members = nil;
})
EDIT 1 I set a breakpoint at NSLog(@"%@", change); This is the stack trace but not really helpful to figure who makes this call.
main -> UIApplicationMain -> NSKeyValueNotifyObserver -> observeValueForKeyPath:ofObject:change:context
EDIT 2 Maybe this is still a bug? http://www.cocoabuilder.com/archive/cocoa/182567-kvo-observevalueforkeypath-not-reflecting-changes.html
回答1:
I am running into the same issue where the "implicit" assignment (and hence the notification of the KVO observer) apparently occurs only as part of deallocating MOs: I save a child MOC, then release it, then iOS releases its MOs. I assume that it then sets one-to-many relationships temporarily to NSNull in the process of deallocating related MOs (where delete rule cascade applies).
So next to change kinds for insertion and deletion my KVO observer now also accepts NSKeyValueChangeSetting and asserts change[NSKeyValueChangeNewKey] == NSNull.null. Call it a pragmatic solution.
来源:https://stackoverflow.com/questions/11835607/kvo-for-one-to-many-but-nsnull-object-passed-into-observevalueforkeypath