Multi window cocoa application - cocoa

If there are multiple window in an application how do I pass values between them?
My first approach would be to create a NSWindowController for any window, and assign these controllers to the Application Delegate.
Am I on the right way? What do you suggest?

Yes, your technique is fine. If you are creating a document-based application you can also do this in your NSDocument subclass.

Related

NSMenu initializer or didLoad equivalent?

I'm trying to build a menubar application on OS X with the NSMenu being shown when the menubar icon is clicked having a custom amount of NSMenuItems. The amount is specified in a settings window and I thought the best way of carrying this number over would be to save it to NSUserDefaults and sending a NSNotificationCenter notification when the value has changed, so the controller in charge of setting up and holding the data for the NSMenu can load this value from the defaults when the notification is received.
The problem I'm experiencing here though is that I'm unsure how to tell the menu controller to subscribe to the notifications. Since I just subclassed NSMenu I don't really have an initializer where this can be done. Or an equivalent to a didLoad method that NSWindowControllers have.
Another option would be to maybe have the menu controller be a singleton and speak directly to that without going through the notification center. Or have a reference to it in the app delegate which would amount to the same thing here.
Or maybe I'm overthinking this entirely and there's an easier way of working with this?
Thanks for any help and tips!
Of course NSMenu has an initializer. All classes do.
Probably, you instantiated your menu in a NIB. In that case, loading the NIB will initialize the menu by calling -initWithCoder:, which NSMenu implements as part of adopting the NSCoding protocol.
If you're instantiating the menu in code, then you must be calling an initializer as part of that (you call [[NSMenu alloc] init...], where init... is some specific initializer).
Your scheme with notifications should work fine.
You could also have your app controller mediate between your settings window and the menu. It would have an outlet to the menu so it could call any appropriate methods, including ones added by your subclass.

Where to put MainMenu.xib selector?

I have a new project I am working on in Xcode 5.1 and I have been using Interface Builder to create and bind most of my layouts. I customized the default MainMenu.xib to contain the menu items I want but I cannot figure out how to bind the selectors for each menu item.
The project has a MainWindow.xib and a MainWindowController that is used by my app delegate and the controller is where I would expect the menu selectors to go, but I don't know how to do that.
The drag-and-drop connections panel will not work with the controller.
The MainMenu.xib's owner is the NSApplication, which doesn't seem right for the selector.
How do (and where should) I handle the MainMenu.xib actions?
Note: my question is very similar to this one but since I have done everything in IB and the accepted answer is in obj-c, the answer is of no use to me.
In my own project, I have a MainMenu.xib and a MainWindow.xib file.
MainMenu.xib is the default starting xib file when one isn't using a storyboard for an app. That's why NSApplication lives in there, it needs to be instantiated.
My MainWindow.xib is owned by my own MainWindowController implementation.
For the various menu items in MainMenu.xib, I am pointing those items at my AppDelegate (which is the true file owner for MainMenu.xib), and with those IBActions I'm firing off methods in other objects, notifications to other objects, or instantiating objects to get whatever task done that's associated with that menu item.
If you have additional classes & objects instantiated within MainMenu.xib, you can add IBActions in those classes and connect the menu items directly to them.

High-Level App Design/Architecture

I've done a fair amount of iOS development in the past couple of years, so I'm pretty familiar with iOS architecture and app design (everything's a ViewController that you either push, pop, or stick into tab bars). I've recently started exploring proper Mac app development and feel a little lost. I'd like to really just have a sanity check and maybe some advice as to what the proper way to build an app like this is:
I'd like to build a library-style, single window app, that will spawn additional windows during its operation, but not as full-blown documents. The main window will be laid out much like OS X Lion's Mail.app, with a three-wide split view containing:
A source list, or high-level topic selection
A list view of items pertaining to the topic selected in the first pane
A detail view, which shows the details of the object selected in the middle pane
Like I said, really similar to Mail.app as far as looks go.
My question is really how to glue all this together from inside XCode. Here's where my confusion lies so far:
The default project generated a NIB with a main menu and window. I like to encapsulate functionality, so should I make a window controller for this window and somehow hook it up in Interface Builder, or does window-specific functionality belong somewhere else?
If possible, I'd like each of my three panes to be separate view controllers. I created three NSViewController subclasses (XCode automatically generated NIBs), and added (to the main menu/window NIB) view controller objects with each class specified, hooking up each one's view property to one of the three Custom View generic NSView objects I dropped into the NSSplitView. When I tried to set each view controller's NIB, only the main menu/window NIB appeared in the drop-down, and typing the desired one by hand seemed to have no effect (the view's contents didn't actually appear when running the app). This makes me think I'm doing something wrong.
I'm a little fuzzy on what types of views I should use for each of the first two panes. I'll obviously build a custom one for the final pane, but it seems like the first two should be present in the Cocoa framework already.
Anyway, if I'm doing completely the wrong thing, don't bother addressing my questions; just tell me what I should be doing instead. I think I just need a proper Mac developer to point me in the right direction.
With regard to your first question, you don't need to use the main window that Apple supplies in MainMenu.xib. If you want, you are free to delete that window from the nib and then instantiate an NSWindowController in your applicationDidFinishLaunching: delegate method which then loads and controls the main window.
You are definitely confused about NSViewController, which is not really all that surprising, since you might assume that it works like UIViewController.
In fact, NSViewController is completely different to UIViewController and does not have the same level of Interface Builder support. You can't place a view controller in a window in IB, for example, whereas this is standard practice on iOS. NSViewController is a relatively new class on the Mac and generally you use it to load views programmatically and manage the view content.
The class that most closely maps to UIViewController on the Mac is NSWindowController. This has been around a lot longer than NSViewController and in fact many Mac apps don't use NSViewController at all.
Generally, each window in your app should have a window controller managing it. You can use subclasses of NSWindowController to handle a lot of the functionality for each window.
If you want to use NSViewController, then you should use your window controller to manage those view controller objects. This is generally done programmatically due to the aforesaid lack of Interface Builder support. Each NSViewController instance loads its view from a specific nib file. You generally don't add view controllers in Interface Builder.
For your source list you would generally use an NSOutlineView if you have multiple sections or an NSTableView. These two objects are used whenever you need a list of items. NSOutlineView is hierarchical, whereas NSTableView is flat.
I hope this helps.

How to access items in the main nib from a document nib?

I'm making an NSDocument-based application in which I have an inspector window. This inspector window is part of Pwnshop.nib which is my main nib. I have another nib called 'Document.nib,' which is the document window. I want to be able to change the inspector based on which document window is the active one, sorta like Interface Builder's inspector. The problem is that I want to access an object in another nib. Note that there are multiple document windows, but only one inspector window.
Could anyone help me?
This is essentially the same question as found here. The answer is the same, too. You need to read the documentation and learn about Communicating with Objects and plan your architecture so that you get get to some universally-reachable controller (eg [[NSApp delegate] myInspectorController]) from your NSDocument instances.
I can recommend both this and this article (both from Cocoa with Love) for a fundamental lesson in how to structure a Cocoa project. They will answer all of your questions and get you started on a path to building applications the right way.

How to use NSWindowController?

I'm looking in to using NSWindowController and I just can't think how to get it working. How do I start using it?
It's difficult to answer this question without knowing what you're trying to do. However, if you are writing a document-based application, an NSWindowController is automatically created for each window you create, so you don't need to create one specially.
The way I use NSWindowController is I create a different subclass for each type of window in my application. For example, I might have a 3D application with an AppWireframeWindowController and an AppPreviewWindowController. Each subclass automatically loads the correct nib file, and has code that hooks the document's data to the views in the nib.
If you are using storyboards you can connect an NSWindowController subclass up in IB. Otherwise if you are using nibs and have just the default template for a Mac Cocoa app then you may need to make it in code or just use a subclass of NSWindow.
Otherwise you can create a new NSWindowController and check the 'Also create XIB file for user interface' and it will give you the nib and also the NSWindowController subclass. It is basically a new nib where 'File's Owner' is your NSWindowController and the Window is the .window object inside the NSWindowController and the delegate is also pointed there.
You may be able to modify that.

Resources