Search code examples
iphoneios4uiviewcontrollerthree20storekit

What is the recommended way of presenting an UIViewController modally from anywhere?


In many applications I wrote it occurred many times that I had to present a controller modally from some class where I had no reference to the current visible controller. (e.g. A StoreKit transaction observer that presents a controller used to display download progress of the products).

With Three20, I can use the - [TTNavigator visibleViewController] to get the job done, but what if I don't want to use the framework? Should I reimplement a custom function that acts like TTNavigator? Is there maybe a similar method in Apple APIs? Could it be better to, for example, create a common parent class for all the controllers in my application and then use NSNotificationCenter to handle all the application-wide notifications? (This of course would have the side effect of having unrelated code in one class)

I'm really surprised Apple didn't provide this basic functionality in his standard APIs. Or maybe the fact that this problem is recurring to me is a sign of poor design practices?


Solution

  • A few thoughts, not necessarily guaranteed to be correct but perhaps will get you in the right direction: If I understand your problem correctly, basically you have some concrete action that at some point (say upon completion) needs to display a modal view, but said action doesn't have a reference to the view controller that's currently on the screen (for example, maybe you're doing a task in the background and letting the user still navigate through your program, and want to alert the user on completion).

    I guess how you would work around this would depend on the overall architecture of your application. Most apps will have some root view controller that controls navigation: perhaps you've got a UITabBarController that you create in your app delegate, and all navigation come off that controller. You could just display your modal view controller through this top level view controller (you'd probably be doing this inside your app delegate).

    Alternatively, you can let go of the idea of displaying modal view controllers and attach the view directly to your application window. If you look at a fairly popular library such as MBProgressHUD you'll see you can attach the modal loading views offered to the app window, in which all your view controllers sit.

    So there are a number of different strategies for achieving what you want. I wouldn't necessarily say your problem is the result of a poor app design, since there are scenarios when you could conceivably need to display some modal dialog and not know what view controller was currently visible. That said, in the example you give - a StoreKit transaction observer that shows download progress - one would assume it would be triggered after a discrete action (purchasing a product, for example), and you would know which view controller that had been triggered from.