UIViewController Looks Out for Itself, Not Its Ownon 23 March 2011

A difference exists in iOS between a UIViewController and a navigation controller (UINavigationController + UITabBarController). One is being used to control views, the latter is used to control collections of view controllers. This fundamental difference creates a rift for the purposes of a recent iPad project.

Screenshot from Xcode of the default Projects not allowing a UINavigationController to be used as the basis for an iPad app

The main problem is that Apple and Xcode do not recommend that a UINavigationController be used as the main iPad app view controller. It strikes me as strange, though the main reason I could find from the HIG is that an iPad app should do everything it can to not change fullscreen views, or more succinctly from the Apple Human Interface Guidelines:

When you perform fewer full-screen transitions, your iPad app has greater visual stability, which helps people keep track of where they are in their task. You can use UI elements such as split view and popover to lessen the need for full-screen transitions.

The HIG has guidelines, not hard and fast rules. Apple’s app “Remote” does not follow this convention (an example that scrapes the bottom of the barrel). However Apple does consider this to be an “OK!” practice when used with a UITabBarController because the buttons at the bottom illicit an expected behavior that the whole screen will change.

UITabBarController example for switching full-screen views in an iPad app, Apple’s App Store app to be exact

The code in problem–causing question is being written to be reused in a various number of situations. The issue is UIViewControllers do not pass on rotation information to their children. Other developers may not know this fact when using the code and will try to figure out why their view controllers are not responding to rotation orientations. UINavigationControllers, conversely, do pass on orientation changes. UINavigationControllers also—through Apple code magic—set the read only variable parentViewController on the rootViewController that is used.

So to prevent the following code from being written each time for other developers to fix the UIViewController in a UIViewController issue.

- (void)willRotateToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
  [self.childViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

- (void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
  [self.childViewController willAnimateRotationToInterfaceOrientation:interfaceOrientation duration:duration];

- (void)didRotateFromInterfaceOrientation: (UIInterfaceOrientation)fromInterfaceOrientation {
  [self.childViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
// ...etc

Sounds like a blast, especially if any of those methods requires case–coding.

Interface orientation changes may not be the only events that are not passed on to children view controllers, however it is one of the features of a UIViewController that is sorely missed when contained inside of another view controller.

If you enjoyed this, use this shorter link to share: http://the.ichibod.com/s/vcalone