Search code examples
objective-ccocoareferenceweak-references

If a child object is released in the dealloc of a parent object, why would the child object's weak reference to the parent be nil*


*because the child is released within the dealloc of the parent, wouldn't that imply that the parent object still exists, and that the child's weak reference back to the parent should still be valid?

I have a parent object, a NSViewController subclass, which owns another object, a NSWindowController subclass.

@interface MyViewController : NSViewController
@property (strong) MyWindowController *myWindowController;

The NSWindowController subclass has a weak reference back to the NSViewController

@interface MyWindowController : NSWindowController
@property (weak) MyViewController *myViewController;

Inside of MyViewController, I have overridden -dealloc:

-(void)dealloc
{
   [self.myWindowController close];
   self.myWindowController = nil;
}

And inside of MyWindowController, I am adding/removing observers inside of the init/close methods.

//INIT:
[self.myViewController addObserver:self forKeyPath:NSStringFromSelector(@selector(selectedObjects)) options:kObservingOptions context:nil];


//CLOSE:
[self.myViewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(selectedObjects))];

Now here's the confusing part.

The order of operations on deallocation goes like this:

  • -[MyViewController dealloc]
  • -[MyWindowController close]
  • -[MyViewController removeObserver:MyWindowController]

BUT, at the point of -[MyWindowController close], the weak reference to MyViewController is nil. Even though it was MyViewController that called close in the first place.

This causes issues because the observer isn't properly removed, and later throws exceptions and sometimes even crashes.

What it looks like, is that the retain count to MyViewController had already been decremented to 0 before the -dealloc is called, so MyWindowController's weak reference to it gets set to nil. But that doesn't make sense to me because it would seem like the retain count would decrement after -dealloc, and also even if that weren't the case, would the weak reference be nil?

It may be possible that this is just a weird interaction w/ NSViewController owning a NSWindowController, but that doesn't make much sense to me either

Why is the weak @property == nil?


Solution

  • From Apple's documentation on ARC:

    A weak reference does not extend the lifetime of the object it points to, and automatically becomes nil when there are no strong references to the object.

    Note, that it doesn't say "when an object is deallocated." If an objects dealloc method is being called, then all strong references have, by definition, been removed.

    Furthermore, you shouldn't be calling methods on objects that have already been deallocated. You should find a way to unregister your observer before the object is deallocated.