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.
Related
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.
I've been learning about when to use WindowController and when to put stuff in the Document object. Looks like Document can work fine as a Controller if you have a simple interface. I have a simple interface in my application, but is it a good practice to put IB outlets into WC anyway? What would be a scenario when you would NOT want to use a WC?
Here are some scenarios:
A document object you intend to use with multiple windows (as commenter noted above) or having different views
A document object you could potentially open and process without displaying a window at all
An application with so much controller code that it's difficult to manage with a single class
During window initialization, the the document will instantiate the window controller.
After that happens, part of the point of separating the model controller and view controller is removing the document's dependency on the window.
As you refine your design, take a look at places where the document needs access to the window, and consider whether you can implement that functionality a different way, for example, by handling it in the window controller instead of the document.
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).
I'm going through a refactoring and reorganization of my application at the moment. I've realized that some of the separation between models and views, and their controllers has diminished and I wish to do some cleaning up.
I have several key classes used in my app: NSPersistentDocument, NSWindowController, and a model class.
The NSPersistentDocument class acts as a "model-controller"; it owns an instance of the model class, and manages all interactions with the model.
The NSWindowController class acts as a "view-controller"; it owns the main window, and manages interactions of the views within the main window. This class is also the File's Owner for the nib file in which the Window is defined.
The problem I see here is that I don't have a real "controller". My current design forces the model-controller and view-controller to know about each other. There is no meditating object between the two, and due to this, my model and view are not clearly separated, which makes supporting multiple views or models a problem.
I would like to move functionality from both of my existing controllers into a new "controller" class which would act as a controller between the model-controller and view-controller. In the end, this is still just the MVC design pattern, with just a little more structure.
However, I am having difficulty figuring out how this would fit into Cocoa's document-based app architecture.
The biggest question I have is where and how would this new controller object be created?
How does this fit into Cocoa's architecture?
Am I fighting against Cocoa's architecture, and is there a better way to do this?
Thanks.
Great instincts on having a "model controller" and a "view controller". That's a very good mental taxonomy for how the M's and the V's usually hang together. But you can still have the pure "C" in the MVC to tie the whole operation together, as you note.
If you're talking about one controller, for the app:
Think of the (big-C) Controller as the thing that grows out of your app's main() function-- in older Cocoa tutorials this object is often called AppController. It might be the delegate of UIApplication, or not, but if it's not, you should consider creating such a master controller in the applicationDidFinishLaunching: method of the app delegate in your project. That AppController can then set up (and own) the model objects and set up (and own) the root view controller, from which your UI springs.
If you're talking about some mediating component that there are multiple instances of, one for each model/view "pair" in a document architecture, then just make something like that up also. DocumentController is the kind of name you want, although Cocoa has one of those already that may or may not reflect the kind of functionality you need. "DocumentManager" is another candidate name.
Sounds like you need to pick up a copy of Cocoa Design Patterns, answers these questions and then some.
Chapter 2 deals with the MVC pattern using an ArrayController as the model controller (rather than the persistent document model-controller you are using).
To lay the groundwork for this question, I'm going to state that I'm getting my definitions for MVC, MVP, and Passive View from the following:
Model View Controller (MVC)
Model View Presenter (MVP)
Passive View (PV)
Apple has always stated that it uses the MVC design pattern, but I noticed in OS X 10.5 we've gotten NSViewController, KVO, bindings, etc., objects that seem to behave more like the Passive View design pattern. Is this where Apple wants us to head? I want to plan out my code in a manner that plays as well as possible with Apple's chosen design patterns, which is why I want to know where Apple is headed. Does anyone have a clue?
Any code of any complexity has many places where different patterns may apply. MVC is prominent in the Cocoa documents because it explains the relationships between your functional code (the model), your UI code or IB design (the view), and the Cocoa services that tie them together (the controller). That's worth emphasis, particularly in the introductory dox, because you need a little "wake-up call" to stop thinking you have to write it all yourself, and start thinking about how to design your unique parts, and trust the framework to do its plumbing job.
The variant definitions of MVC are legendary, and it's worth pointing out that MVC is not described in the canonical "Gang of Four" book, "Design Patterns." It's also worthwhile to admit that Cocoa's "MVC" model is not the same as the SmallTalk 80 MVC (which is where the terminology originated).
It's probably also worth pointing out that "GoF" actually uses the word "pattern" to denote a particular style of documentation, not the abstract way of designing code that the pattern describes. It's too bad that this usage has largely been lost. If we all understood the word that way, then I could say "it would be really useful if someone would actually write up a pattern for Cocoa's MVC." Then we wouldn't all be so confused!
Cocoa is based on MVC (as Apple defines it), and has always been on a trend of doing more and more for you. Here's how it is currently.
View layer: NSView, NSWindow, NSCell, their subclasses, and CALayer
Controller layer (since 10.3): NSController and subclasses (predominantly NSArrayController)
Model layer: Traditionally, you had to do this entirely yourself, but since 10.4, you may be able to use Core Data.
Bindings are powered by KVO (and KVC), and are the glue that bind the three layers together. You bind the views to the controllers and the controllers to the model.
I wouldn't say Cocoa follows the passive view pattern as it's described there. It's saying that the controller does all the work in preparing the view and sending change notifications. In Cocoa a view object will typically respond to KVO notifications (through bindings) from the model, refresh data from the controller that it's bound to, prepare it through data formatters or value transformers, and finally display it on the screen.
Cocoa follows MVC pretty well, although typically the 'controller' aspect is divided into view controllers and model controllers. You can read more about this here. If you have any specific examples on where you're confused, maybe I can provide more detail on the way Cocoa does things.
From the same guide, this section explains some additional design patterns you might find useful. In my own experience though after working through a few projects MVC in Cocoa tends to come pretty naturally, I wouldn't be too concerned about it.
I don't think that Cocoa/OpenStep ever really followed MVC as it's described in, for instance, SmallTalk 80. The SmallTalk Controller is really something which is responsible for interpreting user interaction with the View, which in the case of Cocoa is handled by NSControl and therefore by the View layer (perhaps it's decomposed that way inside the framework, but we're not supposed to peek inside; that's what abstraction is all about :-). In relation to those links of yours, the Controller layer in Cocoa really does fall under the Presenter banner, particularly when considering the various NS*Controller classes from Cocoa Bindings. Those really are a shuttle between a view layer and a model.
In my own applications I tend to have four distinct layers, even in places where they aren't explicitly separated; the view, presenter, service and model. Then the "presenter controllers" and the "service controllers" have entirely separate purposes; the logic and processes are in the services, and the workflow and use cases are in the view controllers. In terms of packaging, if you're into that sort of thing, the services and model together represent an abstract "things to do on stuff" which can be context-independent. The presenters and views represent the "and this is how a user of a Mac OS X application would like to use it" which is dependent upon the lower package, and encapsulates AppKit-specific (and AHIG-specific) classes and behaviour.
The apple docs actually explain MVC better than anything else I read. Basically the confusion related to MVC is because it is a compound pattern. It consists of many basic patterns. Although MVC was not discussed in Design Pattern by the Gang of four, the basic patterns were.
The main difference I think is that in
the Apple world the Controller is a
mediator pattern in addition to what
it normally is.
So unlike the traditional approach
models in Apple's world don't notify
views of change. They don't notify
anybody in fact. If you want to change
a model you have to do it through the
controller to make sure everybody is
notified of changes.
I think this approach is much better than the traditional one. It puts no constraints on the model objects. They don't have to implement any specific interface. They just have to solve domain specific problems. So you can very easily reuse them in other applications.
It is mainly the controller objects which have to be rewritten in this approach. Of course Apple changed that with bindings. But if you don't use bindings then Controllers is application specific.
Using Apple MVC in C++
I actually followed Apple's design when programming applications in C++ using Qt. Views are QWidget's. I put all code that has to do with appearance in a QWidget subclass. Then I make my controller a QObject subclass and have it create the view objects and connect signals from the QWidgets to slots in my QObject Controller. My model class is a regular class that don't inherit anything from Qt and implement the business logic. It gets modified by the controllers slots.
Alternatively the QWidgets can be created outside of the controller, so you can reuse the controller for other types of views.
Not sure if this helps anybody, but I think it is sometimes easier to think of Cocoa patterns in terms of C++, because we are used to getting pattern explained in terms of a statically typed language like C++ and Java.
Uh-oh. MVC = the most misquoted pattern ever. I have read at least 5 different definitions of it.
You may want to read this article by Martin Fowler