OS X 10.10 KVO default behaviour change when observers not removed
OS X 10.10 KVO default behaviour change when observers not removed
- Subject: OS X 10.10 KVO default behaviour change when observers not removed
- From: Jonathan Mitchell <email@hidden>
- Date: Sat, 07 Feb 2015 21:57:56 +0000
Jens mentioned in a previous thread that he was not quite sure whether to always remove observations or not.
This was bugging me. I always did it, though more out of habit than absolute conviction.
The code below confirms that not removing the observation prior to deallocating the observing object really is toxic.
As shown if linked on OS X 10.9 the code below may run to completion or may terminate with an access violation (YMMV).
If the code completes a warning is logged stating that the observed object still has registered observers.
When we mutate the observed key path the deallocated instance gets messaged, which may or may not be terminal.
If linked on OS X 10.10 then the code never completes.
Either it terminates due to an access violation or it aborts as the previous console warning is now a NSInternalInconsistencyException and the thread aborts.
This issue can lurk in code without causing problems if the observed and observing objects tend to get deallocated together.
One can easily see how refactoring could cause the observed object to outlive its observer and produce instability.
#import <Foundation/Foundation.h>
@interface MGSObservedObject : NSObject
@property (strong) NSString *name;
@end
@interface MGSObservingObject : NSObject
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
MGSObservedObject *observedObject = [MGSObservedObject new];
MGSObservingObject *observingObject = [MGSObservingObject new];
[observedObject addObserver:observingObject forKeyPath:@"name" options:0 context:NULL];
observedObject.name = @"Laura Palmer";
BOOL removeObservation = NO;
if (removeObservation) {
[observedObject removeObserver:observingObject forKeyPath:@"name" context:NULL];
}
BOOL deallocObservingObject = YES;
if (deallocObservingObject) {
observingObject = nil;
}
BOOL pokeObservedObject = YES;
if (pokeObservedObject) {
observedObject.name = @"Ronette Pulaski"; // on 10.9 observer may still register change or we may crash, who knows!
}
}
return 0;
}
@implementation MGSObservingObject
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"observed : %@", [object valueForKeyPath:keyPath]);
}
@end
@implementation MGSObservedObject
@end
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden