2
votes

I created a NSWindow xib file that I want to open on click of a button in another window.

Now, to control the behavior of the NSWindow, I dragged an object from Library in xib and changed it to subclass of NSWindowController (i.e. ListingWindowController) that I defined in XCode.

Similarly I also created a subclass of NSViewController (i.e. ListingViewController) to manage the NSView inside the NSWindow. To do this, I dragged NSViewController from Library in xib and changed its class to ListingViewController.

@class ListingViewController;

@interface ListingWindowController : NSWindowController {
    IBOutlet ListingViewController *listingVC;
}

@property (nonatomic, retain) IBOutlet ListingViewController *listingVC;
@end

I connected window and listingVC of my window controller in IB.

Now to invoke this window on click of a button in my launch (first) window, I create the window controller using initWithWindowNibName like this..

- (IBAction) pushConnect:(id)sender {
    NSLog(@"Connect pushed.");
    if (wc == nil) {
        wc = [[ListingWindowController alloc] initWithWindowNibName:@"ListingWindow" owner:self];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeWindow:) name:NSWindowWillCloseNotification object:nil];

        [wc showWindow:sender];
    }
}

The problem is that despite all the bindings done in IB for the view controllers of upcoming window/view, the window and listingVC comes out to be (null), (null) even after the new window has loaded (below code).

- (void)windowDidLoad {
    [super windowDidLoad];

NSLog(@"windowDidLoad = %@, %@", self.window, self.listingVC);
}

Please help why the connections are not working. I'm banging my head against this problem for quite a while now.

PS: I'm coming from iOS programming background. So, I'm assuming the Mac's window/view controller behave similar to iOS UIViewControllers.

TIA..

1

1 Answers

11
votes

Note that:

wc = [[ListingWindowController alloc] initWithWindowNibName:@"ListingWindow" owner:self];

means that self (it’s not clear what self is from your question) is the owner of ListingWindow.nib. This means that self is the one who keeps outlets to objects in that nib file, and self is responsible for releasing the top-level objects in the nib file. This also means that you’re creating an instance of ListingWindowController in your code and another instance inside your nib file since you’ve dragged an object of class ListingWindowController onto the nib file.

This is not how it’s supposed to be.

In the vast majority of cases, a window (view) controller loads a nib file and becomes its owner. It has a window (view) outlet that must be linked to a top-level window (view) in the nib file. Being the nib file’s owner, it must have been created before the nib file is loaded.

In order to achieve this for your window controller, you need to set the file’s owner class to ListingWindowController. You must not drag an object cube and instantiate the window controller inside the nib file. The window controller is the owner of the nib file, so it must exist before the nib file is loaded. You must also link the window outlet in file’s owner to the top-level window object in the nib file so that the window controller is aware of what window it should manage.

Having done that, use:

wc = [[ListingWindowController alloc] initWithWindowNibName:@"ListingWindow"];

instead of:

wc = [[ListingWindowController alloc] initWithWindowNibName:@"ListingWindow" owner:self];

since wc is supposed to be the owner of the nib file.

View controllers work similarly. They’re created before loading the nib file, are responsible for loading a nib file that contains a view as a top-level object, are that nib file’s owner, and have a view outlet that must be linked to that top-level view.

It’s not clear from your question whether you have a separate nib file for the view. If you don’t, then using a subclass of NSViewController is not needed at all — you could use a subclass of NSObject instead. If you insist on using NSViewController to manage a view that’s not loaded from a separate nib file, then you should override -loadView so that you get a reference to the view by some means other than loading it from a nib file, and sending it -setView: so that it is aware of the view it’s supposed to be managing.

Recommended reading: Nib Files in the Resource Programming Guide, NSWindowController class reference, NSViewController class reference.