I have a UI object (a subclass of NSObject
called Label
) that observes a property called region
(subclass of NSManagedObject
called Region
) for three core data attributes:
start
(float)end
(float)name
(NSString
)Label.m
, contains:
-(void) setRegion:(Region *)region {
_region = region;
[region addObserver:self forKeyPath:@"start"
options:NSKeyValueObservingOptionNew
context:nil];
[region addObserver:self forKeyPath:@"end"
options:NSKeyValueObservingOptionNew
context:nil];
[region addObserver:self forKeyPath:@"name"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
context:nil]; // problematic
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSLog(@"%@", keyPath);
}
(I also remove observation as required, in another method)
All this seems pretty standard.
The problem is that when the instruction that is commented with //problematic
is executed, observeValueForKeyPath:
is called 3 times, one for each observed key (start
, end
, name
), even though the problematic instruction only observes the name
key (and should send the notification only once for this key).
Using a specific pointer for the context of each observation does not change this.
This issue doesn't not occur if the problematic instruction is placed at the start of the method, nor when NSKeyValueObservingOptionInitial
is added as an option for the observation of start
and end
.
Of note: Region
is a subclass of an abstract class that defines the start
, end
and name
attributes, and the issue does not occur if the observed object is from another concrete subclass, even though neither subclass do anything special with these attributes (they use default accessors, they don't implement custom setters or whatnot).
Ok I found the root cause. The problem what that the observed object was a fault.
The observation instruction using NSKeyValueObservingOptionInitial
causes the fault to fire, which results in changes of the other (observed) attributes (fetched from the store), triggering change notifications.
Move along, nothing to see here.