views:

97

answers:

2

The Apple documentation gives the following warning regarding using View Controllers to manage part of a screen.

Note: You should not use view controllers to manage views that fill only a part of their window—that is, only part of the area defined by the application content rectangle. If you want to have an interface composed of several smaller views, embed them all in a single root view and manage that view with your view controller.

Now the strange thing is that Apple breaks this advice. UITabBarController, UINavigationController, UISplitViewController all go against this advice. There is a discussion on the Apple forums about what can go wrong if you ignore this advice.

I found a tutorial on how to do this, but the method had a problem with overlapping the status bar which had a fix that seemed kind of dodgy. Other questions have solutions that appear kind of dodgy or advise against doing it.

So given the question is what method does Apple use for its own controllers?

+2  A: 

Apple wrote UIKit, so they can do what they like.

There's a lot of stuff happening under the hood:

  • view{Will,Did}{Appear,Disappear}
  • View rotations (ugh, headache)
  • UIViewControllerWrapperView, which is sometimes the parent of UIViewController.view. Or something.
  • UIViewController.navigationController/tabBarController/parentViewController/modalViewController
  • Popovers are weird. I'm not sure how they fit in.

If you write your own views, you can probably get away with using UIViewController to control them, but don't expect all the magical behaviour that UIKit gives to a "proper" view controller.

EDIT: I probably shouldn't StackOverflow when it's late. I really mean something like this:

If a view is controlled by a UIViewController, the view controller should exist in the view controller hierarchy (i.e. functions like presentModalViewController:animated:). This allows UIKit to handle the complicated bits.

When you use something like [fooSubview addSubview:viewController.view], UIKit may not do all the things it's supposed to do. What retains viewController? What happens if there's a memory warning and fooSubview gets unloaded?

If you set something like viewController.view.frame = (CGRect){{0,0},{320,480}}, you're asking for trouble too: UIViewController sets the frame depending on the current status/navigation/tab/etc bar. It might re-set it, or it might use the frame to decide how to lay out view controllers that you push on top (I've noticed this behaviour; it's messy). If you change viewController.view.transform, strange things can happen on view rotations, since the view transform is what UIViewController uses for orientation (along with the status bar and a pile of other things).

There's only one well-supported exception I know of:

[window addSubview:viewController.view];
[window makeKeyAndVisible];

(In fact, you can stick viewController.view inside a full-window view inside the window; I'm not sure how that works.)

I think in OS 4.0+ you're supposed to set window.rootViewController = viewController instead.

tc.
Apple's controllers work with any view
Casebash
+4  A: 

They also say not to use autorelease pools, but there are autorelease statements throughout their samples. Stick with what's practical. Purity should probably be slightly secondary.

Matt Williamson