Multiple MVC’s and Segues
A common design pattern is for an object to pass a reference to itself (using ‘self’) when sending a message to a delegate so that the delegate can ask our object for more information if they want. For example in the @protocol definition shown below, the FaceView control will set the sender parameter to self when it calls the delegate which handles the smileForFaceView: message:
If you want the fact that your class implements a @protocol to be kept private (i.e. it’s not of interest to an external developer), you are allowed to specify the @protocol name in your private @interface declaration – i.e. the one (normally) in your “.m” file rather than in the header “.h” file. See screenshot.
CGPointZero is a handy, predefined constant for specifying a point of (0, 0) for example when resetting translations passed to gesture handlers. See screenshot.
One MVC (Model, View Controller) should never control more than one screen. If we need to add another screen we should add a new MVC.
We need a “controller of controllers” to switch between multiple MVCs (or screens) for example a UINavigationController. These are sometimes referred to as “container controllers”.
A UINavigationController is a subclass of UIViewController with its own view which can have a title bar and always has an area below it in which to show the view from another MVC. It has no model, it is purely a UI controller.
It has a rootViewController @property which can point to another MVC. This controls what appears in its view (the white area in the screenshots above). It actually “embeds” that MVC’s view into this area. It will change the bounds of your MVC’s view to fit (note your “springs” and “struts” defined in Interface Builder and the view’s contentMode therefore become important during this resizing).
Only in iSO 5 and later. To create a segue in your Storyboard, hold down Ctrl and drag from the source object (e.g. a button) to the destination view controller.
Segues always instantiate a new instance of a view controller. Segues ALWAYS instantiate a NEW instance of a view controller. That’s not a Ctrl-V stutter- I said it twice as it’s important! They always create a new instance from scratch. This allows iOS to dispose of the destination view controllers and free up memory as soon as they’re dismissed.
Segue styles (at the time of writing) can be Push, Modal or Custom (your own subclass of UIStoryboardSegue). Push is used inside a UINavigationController. The iPad also supports Replace which allows you to replace the right-hand view of a UISplitViewController. The style can be set in the Storyboard by selecting the segue and choosing it from a list as in the slide below.
The slide below shows how you can embed your view controller (often your startup one) in a Navigation Controller using the Storyboard interface. The process is similar for embedding within a Tab Bar Controller.
This leads to this…
Here’s an example of how your view could appear embedded within a Navigation Controller. Notice that the “back” button takes it’s label text from the title @property of the previous UIViewController and the title of the current View Controller is shown at the top.
A really quick way to set the title @property is just to double-click it directly in the Storyboard and type it in.
Pressing the “Back” button pops a pushed MVC back to the original, source MVC, but you can also do this programmatically using the UINavigationController instance method:
– (void) popViewControllerAnimated: (BOOL) animated
It’s rare but sometimes handy to call this. In this example, we actually call this function from within the controller on screen – i.e. the one to be “popped” – when its display is no longer required.
All UIViewControllers have a navigationController @property. If the controller is not embedded in a Navigation Controller this will be set to nil. There are similar properties to access other container controllers such as tabBarController.
Triggering a segue from code:
When a segue fires, the destination view controller is instantiated with all its outlets then the following message is sent to the source view controller to give it the chance to pass it information:A common pattern here is to set ‘self‘ as the delegate for the the new, destination controller using the id type. Using the id type is important! DO NOT PASS THE ACTUAL TYPE. Always treat the new View controller as you would treat a view – give it as little information as possible. This approach greatly enhances the portability (“re-usability”) of your controller and code.
You can also instantiate a view controller programmatically using the Storyboard method:
– (id)instantiateViewControllerWithIdentifier:(NSString *)identifier
You can obtain a reference to the Storyboard by calling self.storyboard – as long as self was created from the same Storyboard.
Note the use of pushViewController in this example which assumes the current controller is embedded in a Navigation Controller.
Tip: Did you know a UILabel control can have more than one line of text simply by selecting it in your Storyboard and setting the “Lines” attribute to a number greater than 1?