0

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?

skålfyfan
  • 4,931
  • 5
  • 41
  • 59

2 Answers2

1

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!

Community
  • 1
  • 1
skålfyfan
  • 4,931
  • 5
  • 41
  • 59
1

You should set the title, etc. in -awakeFromNib or -windowDidLoad instead of an -init… method. That way the values will be set before the window is shown and you won't get the flicker.

Wevah
  • 28,182
  • 7
  • 83
  • 72
  • my actual window is dynamic and its title and values are dependent on an object value passed as a representedObject to the controller when opening the window. The window itself is first opened through a selector. I looked at initially doing it through -windowDidLoad but I couldn't see a way to pass my representedObject from the selector method to windowDidLoad? Also, this way would mean I would have to release my window on each close yes/no? Hence why I had to go the route I did to ensure the window was already loaded so I could pre-set the values in the selector method and then show it. – skålfyfan Aug 14 '14 at 19:28
  • my example in the original question was overly simplified when compared to my actual use-case. – skålfyfan Aug 14 '14 at 19:31
  • You should be passing in the values (`representedObject`, e.g.) to your window controller after you init it but before the window is loaded. If you're seeing the window pop up when you init the window controller, make sure "Visible At Launch" is unchecked in interface builder! – Wevah Aug 15 '14 at 02:54