Skip navigation.
 
mlRe: Correct use of NSViewController
FROM : Jonathan Dann
DATE : Fri Mar 21 21:49:33 2008

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