Hooking up multiple NSViewControllers to a nib - macos

I have a window that contains several rather complex views. Right now, I'm using a single NSWindowController to control the UI for the window and all the views. It's becoming a pretty huge class, since it's dealing with the details of each and every view.
The view behaviors are independent from one another though, so I see an opportunity to put the UI logic for each view into a separate controller.
According to the Mac App Programming Guide, this is exactly what view controllers are for:
Use view controllers to divide up the work for managing more
sophisticated window layouts. Your view controllers work together
(with the window controller) to present the window contents.
However, I can't find any documentation or examples on how this idea works in practice. Can I add multiple view controllers to the nib file in addition to the window controller?

If you add the view controllers to the nib, that's where they're going to be instantiated, and you'd add IBOutlets to the window controller (assuming that's the nib's File's Owner) in order to connect them.
In terms of memory, however, that scheme could become expensive, especially the more view controllers you have. You may want to instead consider lazily instantiating them in the window controller, (i.e., doing so only when needed), assuming this doesn't result in an objectionable lag before the view is presented for the first time.
Don't be afraid to try both approaches. One of them may be best for you.
In any case, I applaud you for your decision to factor out all that code into separate controllers. Very nice. Good luck to you in your endeavors.

Related

MVC design pattern in complex iPad app: is one fat controller acceptable?

I am building a complex iPad application; think of it as a scrapbook.
For the purpose of this question, let's consider a page with two images over it.
My main view displays my doc data rendered as a single UIImage; this because I need to do some global manipulation over them. This is my DisplayView.
When editing I need to instantiate an EditorView with my two images as subviews; this way I can interact with a single image, (rotate it, scale it, move it). When editing is triggered, I hide my DisplayView and show my EditorView.
In a iPhone app, I'd associate each main view (that is, a view filling the screen) to a view controller.
The problem is here there is just one view controller; I've considered passing the EditorView via a modal view controller, but it's not an option (there a complex layout with a mask covering everything and palettes over it; rebuilding it in the EditorView would create duplicate code).
Presently the EditorView incorporates some logic (loads data from the model, invokes some subviews for fine editing, saves data back to the model); EditorView subviews also incorporate some logic (I manipulate images and pass them back to the main EditorView). I feel this logic belongs more to a controller. On the other hand, I am not sure making my only view controller so fat a good idea.
What is the best, cocoa-ish implementation of such a class structure?
Feel free to ask for clarifications.
Cheers.
Huge fat controllers are fine.
If necessary, just break off some "purely logical parts" from it and shove them in other "helper classes". And use tricks like categories extensively where you can.
Definitely go with a HFC (huge fat controller) if that feels right.
Then, just get on your engineering bike and slim the hell out of it!
You should definitely not avoid the right structure, the good structure, the structure you want, just because one thing will be too big.
Just slim that big thing down by outsourcing concepts, going nuts with categories, etc etc - every trick in the book.
My belief!
Some reasons to wrap a viewcontroller around your view:
to use it in an Apple API that requires a viewcontroller (popover views, modal views, navigation bars, tab bars, ...)
because the view can be invisible for a while, and so it makes sense to clean it up in low memory situations. The viewcontroller then guards the data that needs to survive such an unload-reload cycle.
because you just like the MVC pattern
I think the second bullet justifies a viewcontroller for your editable content view and another one for your non-editable content view.

What does MVC class organization look like for multiple views and controllers?

The idea of MVC itself seems clear to me but I have trouble understanding how the concept 'scales up' to multiple views and controllers.
It appears that Cocoa takes the approach of the controller being the 'switchboard' between the model and the view. How would the application be organized and function in case of multiple views? If there is a controller associated with every view, would the main application have to keep track of all the controllers it spawns, or each controller would have 'nested' controllers it instantiates, e.g. an application would create a window, the window would create a toolbar etc?
What if the entire application would need to work with the same model, or would you break the models down into smaller ones?
It seems like what I'm really asking is how you would split a multi-window/view application into its logical blocks while retaining the modular MVC structure. I've attempted to look at code from the WordPress iPhone app as well as Adium but both seem to have a relatively large code base that I get lost in.
Generally controllers are implemented hierarchically. For example, in the standard Cocoa Document architecture, you have an NSDocumentController that manages multiple instances of NSDocument. Each instance of NSDocument manages one or more instances of NSWindowController, and each instance of NSWindowController can manage one or more instances of NSViewController.
As you move down the hierarchy, the controllers become more specific and fine-grained in their responsibilities. In terms of accessing the model, Cocoa has several patterns such as the delegate and datasource patterns which you can use to allow the view to draw without the view needing to know anything about the model itself.
Generally the app would have a single unified model, unless it makes sense to have different models (for example, if you needed your app to edit different types of document).

How do you change which view is active in a window?

The program I'm working on right now is a bit cumbersome, as it starts with a central menu, and then once the user chooses an option from it it opens their selection in a new window, when I've got a perfectly good window I can (at least apparently) repurpose to that effect. I've been reading the manual regarding views, and I understand what it's talking about regarding view hierarchy and such, but the method of swapping which view is active is confusing me. What do I need to do to have it "sweep away" the initial menu and replace it with another view containing the content the user selected?
Found a simple solution by using NSTabView to hold each of the views I'm looking for.
It sounds like you don't want to change views at all, but change the model you've loaded into the views.
The simplest way is probably to give the controller for the window a property by which the views can access another controller that owns a portion of the model (one such controller for every item in the menu). Then, you simply switch that controller.
In the setter for that property, you may need to send messages such as reloadData to some of the views, depending on what sort of views they are. Views that observe for changes using Bindings or KVO won't need this.

Simplifying a complicated Cocoa-Touch View Controller

As I wire up my first fairly complicated Cocoa-Touch view I feel like I'm inadvertently slipping back into old procedural patterns and finding it difficult to shake them off...Though fully aware of many of the Cocoa (OO) design patterns I'm afraid I may be subverting them.
As such this view in question is quickly becoming unmanageable and I'm wondering if I might be approaching it the wrong way?!? The view is managed by a subclass of UIViewController. The view itself contains ±10 subviews. Some of these subviews "slide" in and out and contain their own subviews (controls, imageviews, etc) that slide along with them.
Without getting into too much detail I've found that I'm executing most (if not all, including animation) of my management code w/in the touchesBegan/Moved/Ended methods of my root View Controller. And it's become a mess of managing, setting & checking boolean properties. if (editingMode & panelAVisible).... if (editingMode & panelBVisible)... or *if (viewFlipped) { for (MyCustomView view in someArrayOfSubviews)} etc, etc... granted the UI of this app requires most of these views (or their contents) to be touched and moved by the user to different parts of the screen.
The main problems I'm trying to solve seems to be along the lines of: if viewA is present then you 3 views go hide (animated)...or, If viewB is touched then all objects contained in viewC are negative... etc.
Any clever (or rudimentary) OO approach to handling this? Perhaps make the subviews that contain views act as their own mini view controllers? I haven't been able to find too many (any?) examples of that though...
As you suggested at the end of your question, I would recommend having a subcontroller whenever you need logic for a particular subview. The point of a controller object is to keep track of state of the view and to encapsulate all that view logic that you were describing. Interface actions, such as if the user can move to a different screen, can invoke save logic, can create a new document, should be in the controller for that particular view. This will help maintain a separation of concerns between the various controllers and cut your convoluted logic down at the top level.
While it doesn't pertain to iPhone programming specifically, the book Cocoa Programming for Mac OS X contains good examples (especially in the chapter about how to do preference windows) of using subcontrollers and subviews in your application.
I think you should go along your last suggestion, make the subviews that contain views act as their own mini view controllers. Each (sub)view that presents a 'screen full of content' could/should be managed by its own view controller.
Animating between those views can be done with the build in navigation controller (you can actually hide the top bar of a navigation controller) such that you have the default slide animation. Otherwise you could indeed create your own animation while still using that navigation controller.
'The view itself contains ±10 subviews'. Some of these subviews "slide" in and out [..]'. These subviews you're talking about are perfect candidates for extraction from your one monolithic UIView.
The basic OO principle to use is how the navigation controller does it, by pushing and popping views on and off a stack. Each view pushed and popped is handled by its own view controller.
HTH
Edit: I now see you're not specifically talking about iPhone development. Still, have a look how its done there (especially the UINavigationController). You can still get the basic design idea

How many controller classes are typical in a cocoa app?

When designing my application how many controllers should I have? Is it good practice to have one controller for the entire app, the entire window, or for each class? Additionally how many objects are to many created in the doc window in Interface Builder. Tutorials generally have one called AppController. Do full applications typically have App Controller or n*XYZController?
In a non-document-based app, one per window. I'm only talking about controllers you write yourself, not window controllers, view controllers, object controllers, array controllers, tree controllers, or dictionary controllers. (Note that some people do make their custom controller an NSWindowController.) I'm also not counting the app delegate, which owns your root controller(s).
In a single-window app, that usually means one custom controller.
In a document-based app, you generally don't write controllers at all, but write one or more NSDocument subclasses instead—one per document type. Each document object generally owns exactly one window.
Regardless of what kind of app you're writing, you may also want to make controllers for any floating utility panels (such as an Inspector) that you have, although you should consider the alternative: Make the panel be its own controller, as NSFontPanel and NSColorPanel are.
One per window, as Peter Hosey suggests is not a bad strategy, but one man's window is another woman's subview. I prefer to think in functional clusters: if there's two or more related things that need to be done, they might very well need a controller.
But, and this is crucial, you need to be able to think of a good name for your controller: importController, or textFilesImportController or externalFilesDisplayController are names that make clear what a particular controller will do and will not do.
If you cannot think of a good name for your controller take it as a sign that either you do not need it or you are still unclear about your design. In which case you may choose to call it your whateverController until your next flash of insight comes along.

Resources