views:

272

answers:

4

I have a big app with lots of screens, all arranged in a hierarchy, with a UITabBarController at the top, UINavigationControllers below that, and then UIView Controllers below those, maybe with a modal controller somewhere thrown in for good measure.

The user is allowed to pick a start screen from a list. Once selected, next time the app is started it will start from the specified screen and all the navigation will work as if they had navigated there themselves.

Since I can't subclass UITabBarController and UINavigationController, I can't add any ivars to set any initial navigation information.

So what is the best way get the hierarchy set up and the screen of the correct view controller showing under these conditions, and do it quickly?

+1  A: 

You will want to check out NSCoder and save the view hierarchy before exit. This way, to load them up, you just unserialize the view hierarchy and the state should be the same.

coneybeare
An interesting suggestion, but one that I think would have issues. I don't need or want my entire hierarchy saved and restored, just the states of the necessary controllers. If I did this would it save the views as well?
Steve Weller
By implementing NSCoder, you are the one that is in charge of writing what you need, and re-initializing what you need. It is a quick way to save state of your app, not the views themselves. It gives you a way to safely and reliably reload your view controllers etc… without having to make 100 calls to NSUserDefaults or whatever.
coneybeare
One question coney - part of the reason why I do it the way I listed in my answer is because I can save the state of the app as the user progresses through it (setting a delegate for the navigation controller, implementing navigationController:willShowViewController:animated or didShow). With your approach, is there any danger in applicationWillTerminate will either not get called or will not get to finish?
bpapa
you can still save the state as the user goes through it with NSCoder. Check out how Three20 does it. It is a prime example of NSCoder and View Hierarchy saving.
coneybeare
A: 

Save the index of the tab the user wants to have loaded each time, and then when the app starts set the UITabBarController.selectedIndex property to this index and the then you will need to call viewDidAppear on the UITabBarController.selectedViewController. This should trigger the index to set to be visible.

Rodney Foley
That's the easy part. How about all the other other view controllers?
Steve Weller
A: 

I do this by saving a bunch of different values as User Defaults. However, my applicationDidFinishLaunching method is a bit messy as I'm using a bunch of conditional statements to push View Controllers onto the stack, decide which tabs are selected, decide if a modal view is shown, etc.

bpapa
This is how I would like not to end up: a big ball of string in one place. But I'll end up here if there is no other way...
Steve Weller
A: 

I'm not sure what the problem you're describing is. That is, why not just

  • Save either the current displayed-view (if there's only one way to get there) or the user's navigation path (if there are multiple routes) on app exit, then

  • Re-create the view hierarchy as if the user had navigated in your appDidFinishLaunching

...?

So, for example, you might save the class-names of the controllers as they're pushed into the stack then, when the app reloads, create the individual controller classes and push them onto the navigation stack. For tab controllers, you'll need to save the index of which tab was selected at the time.

If your problem/question is more complicated than this, perhaps edit it to explain the specific part where you're getting stuck.

Olie
I know several ways to achieve my goal, but I am asking for the best. In particular, the suggested methods all require a centralized piece of code that knows about the whole app navigation. It will break if the nav changes without being updated. What I am really looking for is a distributed, OO way of doing this.
Steve Weller