Skip navigation.
 
mlRe: Correct use of NSViewController
FROM : Cathy Shive
DATE : Fri Mar 21 22:31:56 2008

Yeah, this is something I ran into dealing with the fact that I have 
several key value observations set up.  The way I deal with it is to 
give my view controller's abstract superclass a -(void)
removeObservations method.  I set it up to work similarly to how you 
use the -(void)dealloc method.  A subclass removes all observations 
that it is registered for and bindings and call's super's 
implementation.  The super call makes sure all the subcontrollers get 
the message as well.

I call this method on the first level controller in from the window 
controller in NSWindow's delegate method, - (void)windowWillClose. 
It's the only place I can think to have this happen at the right 
time.  It has to be before the window controller gets released by the 
document and dealloced.

when the window controller's dealloc is called, it just releases its 
view controller.  the view controller superclass releases its mutable 
array of subcontrollers.

don't retain the window controller in the view controller class. 
This should just be a weak reference.  I think you're doing that right.


so for me:

1,  window is about to close (wish there was a more reliable place to 
do this, but it has to be before dealloc):

windowController:

- (void)windowWillClose
{
   [mViewController removeObservations]; // this causes the method to 
be called all the way down the view controller tree
}

2.  view controller removes it's observations

viewController:

- (void)removeObservations
{
   [wArrayController removeObserver:self forKeyPath:@"selectedObjects"];
   [super removeObservations];
}

3.  The document closes and the window controller is released and 
dealloced:

window controller:
- (void)dealloc
{
   [mViewController release];
   [super dealloc];
}

3.  The first view controller is released and dealloced:

viewController:
- (void)dealloc
{
   [mSubcontrollers release];
   [super dealloc];
}

Everything gets released and dealloced and all observations were 
removed before deallocs were called.

Now, I'm not sure about how to deal with bindings that you set up in 
Interface Builder in terms of controlling *when* the bindings are 
removed and the role of the "representedObject" in all of this. 
Would have to do a little bit of research on that.


On Mar 21, 2008, at 9:49 PM, Jonathan Dann wrote:

> Hi Cathy and Paul,
>
> Thanks to you both for your help, I'm really starting to get 
> somewhere with this now.
>
> I now have a view controller hierarchy that reflects the views in 
> my app.  I've defined my own view controller subclass that I use 
> and an abstract superclass for the view controllers I use in the 
> app.  To this 'ESViewController' class I've added a, parent ivar, a 
> mutable children array and a few indexed accessor methods for that.
>
> To add a new view controller to the hierarchy I use -addChild:
> (ESViewController *)vC which has the side-effect of setting the 
> parent and (originally) the window controller of the child.  The 
> parent will be the view controller that calls -addChild: and the 
> window controller of the 'root' view controller of the tree is set 
> when I first make the root view controller.
>
> Cathy, your suggestion of adding the window controller to the views 
> and their children so I could get the document seemed to work at 
> first, but I kept getting a warning when closing my document.  One 
> of my children view controllers had an NSObjectController with the 
> content binding set to @"file's owner.windowController.document", 
> which worked fine until I tried to close the document.  I was told 
> that the window controller was being deallocated while key-value 
> observers were still registered with it, which I assume was the 
> NSObjectController further down in the view hierarchy.
>
> I think this has something to do with retains, as the window 
> controller was not retained by the view controllers, I couldn't get 
> my head around who should retain who as my -dealloc methods look 
> like this:
>
> // ESViewController (inherits from NSViewController and used as 
> abstract superclass for all my view controllers)
>
> - (void)dealloc;
> {
>     parent = nil; // non-retained ivar
>     self.children = nil;
>     windowController = nil;
>     [super dealloc];
> }
>
> // ESWindowController  (my window controller for my document)
> - (void)dealloc
> {
>     self.rootViewController = nil; // rootViewController is an 
> instance of ESSplitViewController which places a split view in the 
> window's content view)
>     [super dealloc];
> }
>
> My windowController's -awakeFromNib method set the root view 
> controller, which when instantiated created its children, setting 
> their window controllers and parents as such
>
> // ESWindowController
> - (void)awakeFromNib;
> {
>     ESSplitViewController *root = [[ESSplitViewController alloc] 
> initWithNibName:@"SplitView" bundle:nil];
>     [root setWindowController:self];
>     [self setRootViewController:root];
>     [root release];
>     root =  nil;
> }
>
> // ESSplitViewController
> - (id)initWith..........
> {
>     if (![super init])
>         return nil;
>     ESOutlineViewController *oVC = [[ESOutlineViewController alloc] 
> initWithNibName:@"OutlineView" bundle:nil]; // the OutlineView nib 
> has the NSObjectController that causes the deallocation grief
>     ESTextViewController *tVC = [[ESTextViewController alloc] 
> initWithNibName:@"TextView" bundle:nil];
>     [self addChild:oVC];
>     [self addChild:tVC];
>     [oVC release];
>     [tVC release];
>     return self;
> }
>
> - (void)addChild:(ESViewController *)child;
> {
>     [child addObject:child];
>     [child setWindowController:self.windowController];
>     [child setParent:self];
> }
>
> So the way I expected it to work, when deallocating was as follows
>
> windowController gets a -dealloc call
> rootViewController gets released and -dealloc'd
> childrenViewControllers get released and -dealloc'd
> at the end of all this the control returns to the 
> windowController's -dealloc method which proceeds to call [super 
> dealloc];
>
> Some amount of logging later showed me that my windowController was 
> calling super before the children began their dealloc methods, 
> which leads me to assume that maybe the unbinding of the 
> NSObjectController couldn't happen as the windowController to which 
> it was bound was already gone.
>
> So this boils down to a couple of ideas
>
> Why could the window controller complete it's deallocation before 
> the children view controllers have, when they are definitely not 
> retained elsewhere?
> Should the view controllers have retained the window controller and/
> or their parent (instinct leads me to think this would cause retain 
> cycles as the window controller will not call -dealloc as it is 
> retained by view controllers which it needs to release first).
>
> I later changed this code with Paul's suggestion of using the 
> represented object as a pointer to my document subclass and all 
> this went away.  The -addChild method now sets the represented 
> object of the child to that of its parent instead of the window 
> controller.  Am I right in thinking that because of the document 
> architecture the document cannot be deallocated until the window 
> controller is, so deallocating the window controller removes the 
> binding before the document receives -dealloc.  In that case, if I 
> did wish to bind something in my view controllers to the window 
> controller, how can I avoid all this, is there something more 
> sneaky going on in setting the representedObject other than just 
> retaining my document?  Incidentally the window controller still 
> calls [super dealloc] before the children of the root view 
> controller have been deallocated.
>
> Thanks so much to you both for your time, this has really allowed 
> to to break up my code nicely, an taught me a lot.
>
> Jonathan
>

Related mailsAuthorDate
mlCorrect use of NSViewController Jonathan Dann Mar 19, 12:37
mlRe: Correct use of NSViewController Cathy Shive Mar 19, 13:19
mlRe: Correct use of NSViewController Jonathan Dann Mar 20, 02:19
mlRe: Correct use of NSViewController Cathy Shive Mar 20, 08:40
mlRe: Correct use of NSViewController Jonathan Dann Mar 20, 12:35
mlRe: Correct use of NSViewController Cathy Shive Mar 20, 13:29
mlRe: Correct use of NSViewController Paul Szego Mar 20, 23:27
mlRe: Correct use of NSViewController Jonathan Dann Mar 21, 21:49
mlRe: Correct use of NSViewController Cathy Shive Mar 21, 22:31
mlRe: Correct use of NSViewController Steve Weller Mar 22, 04:25
mlRe: Correct use of NSViewController Steve Weller Mar 22, 04:31
mlRe: Correct use of NSViewController Cathy Shive Mar 22, 05:18