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 (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to