Mac App Storyboard - Access Document in NSViewController
I was just wrestling with this myself. I started with the standard Yosemite template and was trying to use [self.view.window.windowController document]
in -viewDidLoad
. At that point, self.view.window
is nil
, so there's no way to get to the document
.
The trick is to wait until -viewWillAppear
. By the time it is called, self.view.window
is populated and the document
is available.
Sequence: -makeWindowControllers
invokes -self addWindowController:
with the storyboard's -instantiateControllerWithIdentifier:
result. -addWindowController:
triggers a call to the VC's -viewDidLoad
before returning. Then, finally, -viewWillAppear
is called (and the document
is available).
This does not directly address the question. But the Q&A link below shows how to access the data model in your document from NSControl objects using bindings, by utilising the preparedObject of the NSViewController.
https://developer.apple.com/library/content/qa/qa1871/_index.html
I set the representedObject for the NSViewController in Document.m as following:
- (void)makeWindowControllers {
NSWindowController* wc = [[NSStoryboard storyboardWithName:@"Main" bundle:nil] instantiateControllerWithIdentifier:@"Document Window Controller"];
NSViewController* vc = wc.contentViewController;
vc.representedObject = self.model;
[self addWindowController:wc];
}
Now representedObject of my ViewController is set to model. Assuming my model has a text property, I can bind any NSControl to that property through ViewController with keyPath: self.representedObject.text
I know the original question was for Objective-C, but for others using Swift, protocols can help. The basic concept can be applied in Objective-C as well.
Instead of reaching back to the window controller, you could use dependency injection:
1) Create a document
property on your window controller and any view controllers that need to access the document (or utilize the representedObject
property that already exists). To make this easier, you could use a protocol to define the document property or to cast the representedObject
property to your document type if you go that route. Make all the view controllers that need to access the document adopt this protocol.
protocol DocumentAccessing {
var document: MyDocument? { get set } // could also use an implicitly unwrapped optional if the document is required to be set for the app to function
}
2) In the makeWindowControllers()
method of your document subclass, after creating your window controller, set its document property to self (as this is the document).
- (void)makeWindowControllers {
MyWindowController *windowController = MyWindowController()
windowController.document = self;
[self addWindowController:windowController];
}
3) Inside your window controller subclass, after you instantiate your view controllers, set the document property of the view controller to the window controller's document property.
4) Now by the time your view controller is loaded, it's document property should be populated.