3

Short version

If I'm writing my own custom split view controller, what do I need to do to make the child view controllers work as expected?

For instance: to send viewWillAppear: and so on.

Long version

Background

A while back I answered the following question:
Switch between UIViewControllers using UISegmentedControl

With the following answer:

The right way to do it is to have the controller handling the UISegmentedControl add the views of the controllers as subviews.

[self.view addSubview:controller.view];

It's your responsibility to send viewWillAppear: and so on.

However, tc. pointed out that this is not as trivial as it sounds:

No. View controllers are not meant to be used like that - controller will miss out on a lot of the UIViewController magic that's taken for granted (namely -view{Will,Did}{Appear,Disappear}: and -shouldRotateToViewOritentation:).

By "magic", I'm referring to everything UIKit does behind the scenes. You also forgot -parentViewController (which is important for things like modal view controllers). Additionally, somewhere in the depths of UIKit, it automatically calls -viewSomethingSomething: for you, so you might get -viewDidDisappear: twice! (I can't remember the exact details, but there's another user reporting that all you need to do is call -viewWillAppear: and the other three methods happen automatically.) The key issue is that Apple doesn't document the "magic" or how it changes between OS updates.

Since then I've been thinking that one should compile a guide for what needs to be present in the parent view controller in order for the child view controllers to work as expected. Apple's documentation doesn't cover this and Google didn't help much either, so now I'm hoping to find this knowledge within the stackoverflow community.

I've written several controllers like this and they all seem to work, but I can't help but wonder if I'm missing out on important view controller magic.

Community
  • 1
  • 1
Erik B
  • 40,889
  • 25
  • 119
  • 135

1 Answers1

1

I think the best solution is "don't do that". Instead of hoping that you can duplicate all of UIViewController's behavior without being rejected for using private API calls why not create non-UIViewController controller objects to manage your subviews? A "controller" is not necessarily a UIViewController.

At a minimum you would need to override or mix in replacement getters for parentViewController, splitViewController, navigationController, tabBarController, and interfaceOrientation (and probably also modalViewController). For each property you would need to make sure that any private setter called by UIKit still works as expected and any changes to those values made by modifying UIViewController ivars directly are also correctly reflected in your implementations.

You're also going to need to figure out how UIKit determines which UIViewController is currently active and should receive view controller lifecycle methods because you need to make sure that these are sent to your container view controller and not only to one of it's children.

You will also have to hope that you haven't just constructed a situation which isn't supported by any of Apple's view controller classes. For example will any of them break if they have a parentViewController but their navigationController, tabBarController, and splitViewController are all nil?

Finally you'll need to keep up with any changes to these private implementation details with every iOS release.

Jonah
  • 17,918
  • 1
  • 43
  • 70
  • I'm sorry, but this is a bad answer. Not doing it is not a solution. Not using a `UIViewController` means that you're not getting any of the view controller magic. – Erik B May 17 '11 at 10:47
  • I realize that this is not the answer you wanted however I don't see a reason to use that "view controller magic" when it will be unreliable. If you're going to need to forward UIViewController lifecycle messages to your nested view controllers anyway its really no extra work to implement them as part of a protocol or superclass rather than inherit from UIViewController. I think I defined everything you need to do to approximate normal UIViewController behavior without using private APIs. I just don't think that it is a good strategy. – Jonah May 17 '11 at 15:40