This is a post down memory lane for you AppKit developers and Apple engineers...
TL;DR:
- When did the default implementation of
NSViewController.loadView
start making anNSView
when there's no matching nib file? (I'm sure that used to return nil at some point way back when...) - If you override
NSViewController.loadView
and call[super loadView]
to have that defaultNSView
created, is it safe to then callself.view
withinloadView
?
I'm refactoring some old Objective-C code that makes extensive use of NSViewController
without any use of nibs. It overrides loadView
, instantiates all properties that are views, then assigns a view to the view controller's view property. This seems inline with the documentation and related commentary in the header. I also (vaguely) recall this being a necessary pattern when not using nibs:
@interface MyViewController: NSViewController
// No nibs
// No nibName
@end
@implementation MyViewController
- (void)loadView {
NSView *hostView = [[NSView alloc] initWithFrame:NSZeroRect];
self.button = [NSButton alloc...];
self.slider = [NSSlider alloc...];
[hostView addSubview:self.button];
[hostView addSubview:self.slider];
self.view = hostView;
}
@end
While refactoring, I was surprised to find that if you don't override loadView
and do all of the setup in viewDidLoad
instead, then self.view
on a view controller is non-nil, even though there was no nib file that could have provided the view. Clearly NSViewController
has realized that:
- There's no nib file that matches
nibName
. loadView
is not overridden.- Created an empty
NSView
and assigned it toself.view
anyways.
Has this always been the behaviour or did it change at some point? I could have sworn that if there as no matching nib file and you didn't override loadView
, then self.view
would be nil.
I realize some of this behaviour changed in 10.10, as noted in the header, but there's no mention of a default NSView
being created.
Because there are some warnings in the header and documentation around being careful when overriding methods related to view loading, I'm curious if the following pattern is considered "safe" in macOS 15:
- (void)loadView {
// Have NSViewController create a default view.
[super loadView];
self.button = [NSButton...];
self.slider = [NSSlider...];
// Is it safe to call self.view within this method?
[self.view addSubview:self.button];
[self.view addSubview:self.slider];
}
Finally, if I can rely on NSViewController always creating an NSView
for me, even when a nib is not present, then is there any recommendation on whether one should continue using loadView
or instead move code the above into viewDidLoad
?
- (void)viewDidLoad {
self.button = [NSButton...];
self.slider = [NSSlider...];
// Since self.view always seems to be non-nil, then what
// does loadView offer over just using viewDidLoad?
[self.view addSubview:self.button];
[self.view addSubview:self.slider];
}
This application will have macOS 15 as a minimum requirement.