Organising view controllers, continued
The last article on this subject (Organising view controllers) started looking at an example. Apple’s ViewController sample illustrates basic use of multiple view controllers. This article completes the work.
Download the source if you would rather skip ahead. Sometimes it’s easier that way. You can see the code in its full context. Snippets and extracts don’t always tell you everything you need to know.
Missing pieces
Where did we leave off? Application delegate and window controller exist but don’t do much. The window controller has a stub for the pop-up action. It does nothing. Of course, the application needs some custom view controllers for handling the view-specific behaviours. The image view has an Open push-button for example. Click this and the controller presents an Open Panel letting the user change the view’s image. Lake Don Pedro looks nice, but perhaps you fancy a change! The table view initialises some names, etc. Custom view controllers will add the view-specific controller behaviour.
However, the biggest missing piece: the view meta-controller itself. The project needs a class for meta-controlling view controllers.
Start simple
What is the most basic requirement? Our test application (View Controller Mark II) wants to say “load a view” given by @"CustomImageView", a string. The meta-control architecture then loads the corresponding nib, constructs an instance of CustomImageViewController and then hangs the result in a graph of meta-controllers. At any time thereafter, any object method with access to the meta-control graph can access the view controller (i.e. [vmc viewControllerForViewPath:@"CustomImageView"] where vmc means the view meta-controller) and, from there, its view, represented object and title. Note, if there were nested sub-controllers, the view-path would read @"CustomImageView.SomeOtherName". SomeOtherName stands for a nested tier of control. In this case though, requirements only need non-nested controllers. Pity.
Let’s take the NSViewController class and bolt on a meta-controller. The new class associates with one view controller (its subordinate controller) and multiple subordinate meta-controllers by name. See diagram below.

The diagram indicates unidirectional associations using directed arrows. The viewController association from meta-controller to view controller is unidirectional, in that direction. Likewise from name to subordinate meta-controller. Names are unique strings identifying lower levels of meta-control. This model forms a graph or tree: a hierarchy of named meta-controllers.
It’s a simple model. Note, no reverse navigation from view controller to meta-controller. Hence no need for new NSViewController subclasses. The hierarchy lives outside the pre-existing view controller framework. Of course, the model supports view controller subclasses, but not for maintaining the meta-control graph.
You might have noticed the diamond shape at the name-end of the meta-controller association; it marks an aggregation. In fact, in this case, it marks a self-aggregation, also known as circular. Some sources say that self-aggregation does not make sense. I’m not so sure. In this instance, meta-controllers are “parts of” other meta-controllers. Aggregation is not a precise concept. Suffices to say there is a strong association between meta-controller parts.
Overlaying some methods
Of course, the diagram above shows RRViewMetaController without methods. So not a very useful class, at present.
Adding methods can prove challenging. It takes judgement, experience, skill, even art. There is never one “right” way. It’s almost like pouring custard over your pudding! You don’t want a thick blob at one side; a smooth even coating works best. Yes, I know, that carries it too far. But I’m sure you know what I mean: behaviour needs judicious placement within a class structure. Methods are little packets of behaviour. Placing them, naming them is as important as implementing them, because in the long run mistakes can have an important impact on maintenance. When the custard goes cold, it gets harder to spread. I’ll shut up about custard now (I must be hungry though I just ate).
Meta-control will need methods for the following function groups.
Initialising and de-allocating
The usual housekeeping work.
* -init initialises an instance
* -dealloc de-allocates an instance
Accessing properties
Every meta-controller controls a subordinate view controller. Other objects need access to this.
* -viewController answers the associated view controller
* -view answers the view controller’s view
Adding and removing from super-views
Every meta-controller directly and indirectly manages a triplet: a view controller, a nib and a view hierarchy. The view hierarchy does not automatically enter any given window undirected. The design requires methods for adding and removing the view, along with any sub-views.
* -addToSuperview:aSuperview adds the meta-controlled view to aSuperview
* -removeFromSuperview removes the meta-controlled view from its super-view
Naming and removing meta-controllers
Accessing meta-controllers’ names, removing them if necessary.
* -namesOfMetaControllers gives all the names of the subordinate meta-controllers
* -nameOfMetaController:aMetaController answers the name of aMetaController
* -removeMetaController:aMetaController removes aMetaController by identity
Resolving and removing view paths
Given view-path strings, meta-controller instances answer corresponding controllers, loading view controllers and views as necessary.
* -resolveViewPath:aViewPath resolves a view path answering an array of meta-controllers
* -removeViewPath:aViewPath removes the meta-controller identified by aViewPath
* -viewMetaControllerForViewPath:aViewPath answers the view meta-controller identified by aViewPath
* -viewControllerForViewPath:aViewPath shortcuts the view controller accessor, answering a view controller for a given view path
Adding these to the class diagram:

Notice the method signatures reflect C++ and Java language styling. Method name comes before arguments and arguments appear in parentheses. Of course, in real life, Objective-C intermingles signature and arguments. Hence you see addToSuperview: as the name, with aSuperView : NSView as the argument-and-type pair. I’ve also skipped the pointer asterisk as implied. I hope it makes sense. Note also, plus prefix means public in this context, not a class method.
Interface, RRViewMetaController.h
Turning the requirements into Objective-C:
// Meta refers to a position beyond, of a higher or second-order kind. Thus, a
// meta-controller controls controllers! Hence, the view meta-controller class
// controls view controllers.
// Notice, the class does not implement a back-reference to the parent
// meta-controller. True, even though they form a tree. View paths specify leaf
// nodes. The class resolves the path by walking from root to leaf, recording
// the journey at each step. This approach obviates references to parent nodes.
// Effectively, the graph of meta-controllers "hovers" above the view
// controllers, retaining them and their view hierarchies. You address leaves on
// the meta-graph using view paths where the names of the path elements
// correspond to the nib names. That implies that you can have the same nib by
// the same name. You can but not at the same tier in the hierarchy unless you
// use a colon to add more context to the name without adding to the nib
// name. In short, name strings of the form myNib:blahBlah loads the nib file
// named myNib but uses myNib:blahBlah to uniquely identify the meta-controller
// within the graph.
I’ve included comments describing the class and its methods. They might be worth reading. I know you’d rather skip. Anyway, notice the method groups.
Resolving view paths, that’s the key method. Given a view-path string, it answers an array of meta-controllers, one for each name appearing in the path. For example, given a string such as @"a.b.c", the -resolveViewPath: instance method walks the meta-controller graph starting at a, then subordinate b, followed finally by c. Resolving constructs the graph along the way. Dots in the view-path string delimit meta-controller names. Names must be unique and correspond to nib names. Loading a looks for a nib named @"a". You reuse nibs using a colon in the name, e.g. view-path of @"a:1" and @"a:2" resolve to the same nib (a) but have unique meta-controller names. Everything after the colon belongs to the unique meta-controller name. Everything before identifies the nib.
In the next article on this subject, I’ll deal with the implementation.
over 2 years later
I feel so much happier now I unsdetrand all this. Thanks!