Setting NSWindowController for the root window? - objective-c

I am playing around with the default XCode template for a cocoa application. By default it has a MainMenu.xib with a window and a menu -- awesome.
I intend to build up my views/subviews in code, so I then create a RootView : NSView and a RootViewController : NSViewController, and bind them up in IB so that my base view in that window is my RootView, controlled by my RootViewController.
Enter my question -- How do I do the same to have a RootWindowController bound to the NSWindow? I had assumed File Owner was the trick, but it's set to NSApplication, which I think is correct. The main goal of NSWindowController in my case is to manage the toolbar based on NSNotifications fired from other services -- is this even the correct design here? I don't think I can do this from my RootViewController since I don't have a window reference, but is that where I should do it instead?

Many times, the application delegate is used as the main/central controller for a non-document-based application. This is a good place. This can be an NSWindowController instance if you like. You can just do away with the existing window in your nib.
Helpful information from the NSWindowController API reference:
You should create a subclass of NSWindowController when you want to augment the default behavior, such as to give the window a custom title or to perform some setup tasks before the window is loaded. In your class’s initialization method, be sure to invoke on super either one of the initWithWindowNibName:... initializers or the initWithWindow: initializer. Which one depends on whether the window object originates in a nib file or is programmatically created.
But if it were me, I wouldn't bother going the NSWindowController route; I'd just add this logic to my app controller (and set it as the app delegate) since this is app-level stuff. No need to add a layer of complexity unless you've got a LOT of main-UI-updating complexity you want to compartmentalize.

Related

Insert Outlets in AppDelegate or Custom Cocoa Class?

I was an iOS programmer and recently switched over to making Cocoa apps for Mac. When creating a project in Xcode, it seems there are two options:
(1) Using the MainMenu.xib default, insert buttons and link to AppDelegate. I have tried creating an NSView class and linking to that with no success.
(2) Creating an NSViewController class and linking the view from MainMenu.xib and any buttons to that.
Which of these methods is better when creating larger applications, with multiple views and windows?
Edit: What would be the best way to start out if not connecting anything to AppDelegate? Create an NSWindowController class with an xib and connect its view to a NSViewController class?
I guess overall I am confused as to which class I start with and what elements (window, views, buttons) to connect to what class file.
You can create a window object in your MainMenu xib and create a reference to it in your AppDelegate class. You will be able access items in it. But this is good only for a little learning.
You should start with an NSWindowController. For a first try, don't make any view controllers yet. Use the xib file and build your first window in the subclass of NSWindowController.
In AppDelegate, create an instance of the new class and open it.
Once you have mastered that, you can define view controllers for parts (or all) of you window's view.
If you need sample code, let me know, but it's a good exercise to work it out.

NSWindow bind load event for control and logic initialization

I just started working on an OSX application, first time in objective-c. I need to make a window that will display all the network interfaces available on the computer.
So far
I have an AppDelegate that pretty much does nothing
I have set the Main nib file base name to my main window, which is a xib, header and implementation file
I made my xib window inherit from my class and added the outlets I needed using right-click drag (worked well, I assumed I was correct until then)
The issue
I can't seem either override or bind the load event of the window, where I want to load the text in my label.
I've seen some people use a NSWindowController, but I don't think I need this.
My question
Is it required to have a NSWindowController PLUS a NSWindow class? I feel there are too many files for a single window. I have the xib and two .h/.m files... If it's not required, how can I get notified when the window loads?
The question wether you need NSWindowController(s) or not depends on the complexity of your application.
If your app is only a small utility using a single window, you might get away with setting up your UI in MainMenu.xib and connect it to some IBOutlets in your AppDelegate.
But the above approach gets messy soon when your app becomes more complex. To tame that complexity, you can create dedicated NSWindowController classes (e.g. one per window). Those window controllers could manage a hierarchy of child NSViewControllers to further split up your complexity.
If it's not required, how can I get notified when the window loads?
The default Xcode template should have created an AppDelegate.m file. You can add code to initialize your UI in
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
At this point the window has been fully loaded and
#property (weak) IBOutlet NSWindow *window;
should point to your window instance.

What's the advantage of using UIViewController as owner of xib?

Most of the time, owners of xib is a UIViewController.
I sort of use it my self.
Still I am confused why.
I suppose, the viewDidLoad and viewWillAppear is kind of the main selling point.
Is that it?
What are the advantage of using UIViewController as owners of an XIB?
A UIViewController object is the main way for views to appear within an iOS window.
Apple provides this as a fundamental, foundational building block (along with so many others) which you can use to build upon quickly and get your app out to market.
And when you subclass UIViewController, you're able to do lots of beautiful customizations which can be collected and eventually turned into (hopefully decent) products. When you subclass a UIViewController, you need to set the "owner" of a XIB file to that subclassed view controller (e.g. ThioViewController), so that way the app knows what object (and user interface) is being instantiated.
Hopefully this isn't too super abstract of an explanation.
First, spend a bit time to understand MVC http://en.wikipedia.org/wiki/Model–view–controller
This is the milestone of Objective-C (not only) development.
UIViewController is controller for all your views (inside this viewController). It provide starting point for you to create views on the screen, manipulate the views, handle actions from views etc.
You can create UIViewController programmatically.
XIB is representation of the screen which you can comfortably operate in Interface Builder to create and customize design of your application screen or one of the screens.
Since XIB represent the screen(view) it must be the controller which controls all the view on the screen - UIViewController or UINavigationController or other type of controller depending of your needs.
Most of time you will subclass UIViewController and use it to achieve you goals.
UIViewController have several subclasses which inherit directly from it (UINavigationController, UITabBarController).
Also UIViewController hav several methods (some of them)
-(void)viewDidLoad
This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.
and
-(void)viewWillAppear:(BOOL)animated
Parameters
animated
If YES, the view is being added to the window using an animation.
Discussion
This method is called before the receiver’s view is about to be added to a view hierarchy and before any animations are configured for showing the view. You can override this method to perform custom tasks associated with displaying the view. For example, you might use this method to change the orientation or style of the status bar to coordinate with the orientation or style of the view being presented. If you override this method, you must call super at some point in your implementation.
Please check Apple documentation for more information
https://developer.apple.com/LIBRARY/IOS/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html

The relationship between UIViewController and UIView

I'm trying to understand how these two are connected. Every time you make a UIViewController does it also automatically come with its own UIView?
Also are these from Cocoa or Objective-C?
UIViewController is a Cocoa Touch class built for the purpose of managing UIViews. It expects to have a view hierarchy, but you don't "automatically" get a view (this is slightly inaccurate; see edit below). Usually you will obtain views by calling initWithNibName on your view controller.
There is some built-in magic in Interface Builder which knows that if File's Owner is a UIViewController (or subclass), there is a property called view. That's about it.
Once you have linked a view controller and a view, the view controller does a fair amount of work for you: it registers as a responder for view touch events, registers for device rotation notifications (and handles them automatically, if you wish), helps you take care of some of the details of animation, and handles low-memory conditions semi-automatically.
Edit: correction—if you don't call initWithNibName or set the view property manually, the view property getter will invoke loadView if view is nil. The default implementation of loadView will see if you've set nibBundle and nibName and attempt to load the view from there (which is why you don't have to call initWithNibName, most of the time), but if those properties aren't set, it will instantiate a UIView object with default values. So technically, yes, it does automatically come with its own UIView, but most of the time that's of little value.
UIViewController doesn't automatically come with a view. You have to make a view in the -loadView method. By default, this loads the view from the nib file you've specified. You can also override this method to make a custom view if you prefer not to use a nib.
Also, the view is not created right when the UIViewController is created. UIViewController uses a technique known as lazy-loading to defer the creation of a view until the view is actually accessed for the first time.

Why does an NSWindow or NSView instance handle its own key events, and not its delegate?

As a newcomer to Cocoa, I am struggling to understand why the generic NSResponder subclasses implement key events the way they seem to do.
In my program, I have an NSWindow subclass which takes up the whole screen, and must necessarily handle key events. There are several major commands which can change the whole state of the program (e.g. pause a timer when the user hits the spacebar) which it does not make sense to have subviews like an NSTextField handle.
It seems to me that the delegate (controller) should get these events. Instead, I find I have to either write a bunch of messy glue code to have the window (via its keyDown: and interpretKeyEvents: selectors) notify the controller, or I have to just move a bunch of controller code to the NSWindow subclass itself.
This is messy and my gut tells me I'm missing something. Is there a cleaner solution?
If you've set it up correctly, the NSWindow's delegate will receive the messages. Cocoa uses the responder chain to forward messages from the first responder -- the key view for key messages, and the view that was clicked/hovered/etc. for mouse messages -- back through the superviews, up through the window, and eventually to the window's delegate. There's a pretty good diagram of the typical responder chain on Apple's site.
You really should never have to subclass NSWindow unless you're implementing some fancy window drawing or something else along those lines. Cocoa provides the NSWindowController class to behave as a controller for a window and its contents.
The usual pattern is to subclass NSWindowController and add your IBOutlets to it, and then use a NIB to lay out your window contents. You make your NSWindowController subclass the class of the File's Owner proxy in Interface Builder. And you also assign the window's delegate to the window controller so that it can become part of the responder chain. Finally, to create windows, you use NSWindowController's initWithWindowNibName: method, which automates loading the NIB with a new window controller as the file's owner.
I'd recommend reading up on window controllers in the Cocoa documentation, because they provide the missing link you're looking for.