0

I was replacing the deprecated +(BOOL)loadNibNamed:owner: method in our macOS app with a more standard initWithWindowNib approach and came across the Apple guide about Document-Based App Programming Guide for Mac. One section particularly drew my attention: An NSWindowController Subclass Manages Nib Files

For records it say:

An NSWindowController object expects to be told what nib file to load (through its initWithWindowNib... methods) because it is a generic implementation of the default behavior for all window controllers. However, when you write a subclass of NSWindowController, that subclass is almost always designed to control the user interface contained in a particular nib file, and your subclass would not work with a different nib file. It is therefore inconvenient and error-prone for the instantiator of the subclass to have to tell it which nib file to load.

This problem is solved by overriding the init method to call the superclass’s initWithWindowNibName: method with the correct nib name. Then instantiators just use init, and the controller has the correct nib file. You can also override the initWithWindowNib... methods to log an error, as shown in Figure 2-4, because no instantiator should ever try to tell your subclass which nib file to use. It is a good idea for any NSWindowController subclass designed to work with a specific nib file to use this technique. You should do otherwise only if you are extending just the basic functionality of NSWindowController in your subclass and have not tied that functionality to any particular nib file.

Figure 2-4  Loading a nib file that is controller specific

Pretty reasonable, let's try it.


Note: There is a question related to the same documentation section, but it has a different problem, asks a different question and is not using Modern Objective-C syntax.


My MainWindowDelegate.h now has:

- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithWindow:(nullable NSWindow *)window NS_UNAVAILABLE;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;
- (instancetype)initWithWindowNibName:(NSNibName)windowNibName NS_UNAVAILABLE;
- (instancetype)initWithWindowNibName:(NSNibName)windowNibName owner:(id)owner NS_UNAVAILABLE;
- (instancetype)initWithWindowNibPath:(NSString *)windowNibPath owner:(id)owner NS_UNAVAILABLE;

And MainWindowDelegate.m now has:

- (instancetype)init {

    self = [super initWithWindowNibName:@"MainWindowWin"];
    if (self) {
        // Initialization code here.

    }

    return self;
}

The only available initializer from the AppDelegate is correctly the init (if I try to use initWithWindowNibName then I get the error 'initWithWindowNibName:' is unavailable). So far so good and it works pretty nicely.

But now I have a bunch of warnings...

For - (instancetype)init { line

Designated initializer missing a 'super' call to a designated initializer of the super class

For self = [super initWithWindowNibName:@"MainWindowWin"]; line

Designated initializer invoked a non-designated initializer


If this is the suggested Apple approach to subclassing NSWindowController why all these warnings? Am I missing the point? How to fix the warnings and maintain only init initializer availability?

Shebuka
  • 3,148
  • 1
  • 26
  • 43
  • Apple does not suggest using `NS_DESIGNATED_INITIALIZER` and `NS_UNAVAILABLE`. – Willeke Mar 22 '18 at 08:28
  • Yes, they suggest to log an error... that is not solving the problem of being still able to see and use `initWithWindowNibName` from another class. With Modern Objective-C syntax we can accomplish this with `NS_UNAVAILABLE`. – Shebuka Mar 22 '18 at 08:41
  • You can't use documentation from 2012 and Modern Objective-C syntax. – Willeke Mar 22 '18 at 08:58
  • Isn't answer questions about topics not covered by outdated or incomplete documentation part of the reason why we are all here? – Shebuka Mar 22 '18 at 09:03

0 Answers0