Search code examples
objective-cmacoscocoainitializationnspanel

NSPanel - Why can I not set my Panel title and data values before showing the window?


Simple structure:

exampleController.h :

#import <Foundation/Foundation.h>

@interface exampleController : NSWindowController {

@public

IBOutlet NSPanel *entryPanel;

@property (nonatomic, strong) IBOutlet NSPanel *entryPanel;

@end

exampleController.m :

#import "exampleController.h"

@implementation exampleController

@synthesize entryPanel;

- (id)init {
    self = [super initWithWindowNibName:@"ExamplePanel"];
    if (self) {
        // Initialization code here.
        NSLog(@"entryPanel: %@", entryPanel);
        [self.entryPanel setTitle:@"TESTING!"];
    }

    return self;
}

randomController.m :

...

- (id) init {

  self = [super init];
  if (self) {

    // loading our example controller if it isn't loaded yet.
    if (!ourExampleController) {
       ourExampleController = [exampleController alloc] init]; 
    }
  }

  return self;
}

...and then later in the random controller within a method I show the NSPanel via:

[ourExampleController showWindow:self];
[ourExampleController window] makeKeyAndOrderFront:self];

My problem is that no matter what, the first time the NSPanel displays and shows itself the title is always still set to the title that it has in Interface Builder! Even though I explicitly set the title in the exampleController init method.

I've also tried throwing an NSLog(@"entryPanel: %@", entryPanel) in the init method for exampleController and at launch it is always NULL. I do not have to ALLOC all my IBOutlets in the init because I am already synthesizing them?

I've double checked everything in interface builder. The File Owner for the ExamplePanel.xib is set to the exampleController class. The window AND entryPanel outlets are both referencing the NSPanel in our xib file. What am I missing ??

Thanks in advance!

EDIT: Just to add. If I open the window (..and see the default IB title) and then close it and reopen it with a method that changes the title - it seems to work! This problem seems to only reside with the window first opening. It seems like my properties are not being alloc'd until the window first opens?


Solution

  • EUREKA!

    As per discussion here: IBOutlet instances are (null) after loading from NIB

    I learnt that the window itself is not loaded when my controller is initialized. Found that surprising since I figured using initWithWindowNibName:@"myNibFile" would also alloc and initialize all outlet properties but since I'm new to OSX Obj-C that appears to not be the case. All the outlet properties are only alloc'd once the window itself is loaded too.

    It's easy to just show the window (which also loads the window if it's not loaded yet) and then quickly set all the outlets to my desired values BUT this was an issue for me since I wanted to avoid that ever so slight "screen flicker" (for lack of a better description) that occurs as the values adjust to their new settings.

    The solution was to find a way to load the controller and load the window without actually showing it first! Then I discovered this: Can you force a NSWindow to load, i.e. before it is presented onscreen?

    Steps to make that happen:

    Add the following to my NSWindowController subclass init method:

     // this loads the window as per link/description above
     [self window]
    

    The key seems to be though to ensure that in your NIB/XIB file that the Visible At Launch is unchecked. If it is checked (default behavior) then the [self window] call above will still show your window when your app launches. Unchecking the above option ensures the above call does not show your window until you explicitly show it yourself!

    E.g. You can define an action button which loads your window:

    [exampleController showWindow:self];
    [[exampleController window] makeKeyAndOrderFront:self]; 
    

    Hope this helps someone else out. Was a head scratcher for a couple hours!