"Infinite Drill-down" with UINavigationController - objective-c

Can anyone suggest an article or perhaps an example of how to create an "infinite drill-down" with UINavigationController like you see in the Facebook, IMDB and BrightKite apps?

The UINavigationController is designed to be used this way. If memory becomes an issue, the nav controller will release hidden views and reload them when the time comes to navigate back down the stack. Apple recommends you load your UIViews from a NIB for this reason.
http://developer.apple.com/iphone/library/featuredarticles/ViewControllerPGforiPhoneOS/NavigationControllers/NavigationControllers.html#//apple_ref/doc/uid/TP40007457-CH103-SW28
Scroll down to item #4, "Configure the view for your root view controller."

Never having done this... I would approach this by keeping a stack with a light-weight object containing the contents of the previous view (perhaps just a URL?). Rather than just push on a new UIViewController to the UINavigationController, you would pop your current one, without animation, then push on the new view. However, I don't think this would properly handle the nice animation.
Another way that comes to mind would be to manipulation the viewControllers array of UINavigationController. After pushing on a new view, just remove the previous view from the array. That way the UINavigationController stack would only ever be 1 or two elements deep. Handling the back button would create the proper view, insert it into the viewControllers array, then pop off the current one. Your state would be managed by the lightweight object stack, not heavyweight view controllers.
-dan

Related

addSubview: re-writes the navigation stack?

I'm working on a app which uses the controller containment pattern as described in the View Controller documentation in the iOS SDK.
I've written the controller container, and it works great. My controller is basically containing two sub views and it displays them both at the same time, sliding one over the other depending on what the user is doing. Works wonderful.
Now, I want to use this container controller in a navigation view. This is to get push segues to work. In effect, from my contained controllers, I want to be able to use the navigation stack, push a new controller on, and pop when the user is done.
However, I have noticed that if the navigation view is instantiated with my container controller as the root container, things fall apart.
In particular, I have noticed this:
In the iOS documentation, container controllers call addChildController: and then addSubview:. This seems to break the navigation stack, as the push segue does not work - it behaves like modal. I believe it does this because addSubview resets the navigation stack.
I confirmed this by replacing addChildController and addSubview with [self.navigationController pushViewController...]. I confirmed it is a problem with addSubview because I can reproduce the issue when I omit the call to addChildController.
When I do this, the navigation stack works properly. But of course, my container controller does not, as only the "most recently pushed" controller is visible.
I'm doing this because in my contained controllers, I want to push a new controller onto the stack, and when the user is done, I want to "pop" the stack, without reloading the "previous controller".
Using a modal segue reloads the previous controller; using a push controller does not.
I cannot find any documentation on the behavior of addSubview and it's effect on the navigation stack.
Thank you in advance for any light you guys can shed!
I'm having a bit of trouble completely understanding what you are doing, but I think that what you want to do is exactly what I'm doing.
I have a UINavigationController that has as its rootView a container UIViewController. That controller adds children per the normal methods. One of those children views pushes other views that may get popped.
One of those pushed views COULD message the appDelegate and make itself the rootViewController if it wanted to. In general, as long as you keep a strong reference to a view controller, you can remove it from whoever 'owns' it, and muck around with the navigationControllers viewControllers array to your hearts content.

How/whether to simulate a UINavigationController pushToViewController method

I’m designing the interface for an iOS app in which there are both hierarchical navigation modes and arbitrary view-swapping modes. The layout of any given view in one mode is distinct from that of the corresponding view in the other mode.
I want the user to be able to switch back and forth between these modes. Say an isolated subview has a corresponding detail view that is 2 levels down in the UINavigationController’s hierarchy. The user should be able to switch directly to that navigation detail view. From there, he should be able either to navigate up and down the UINavigationController hierarchy or to switch back to the isolated subview from which he came.
UINavigationController has a method popToViewController:animated: that will let you skip levels as you navigate back up the hierarchy, but it has no corresponding pushToViewController:animated: that would let you jump directly to a lower level in the hierarchy. That makes sense — the nav controller must push the intervening view/s onto the stack before it displays the target view. But the regular push methods display the intervening view/s, which I assume will cause a visual flash as well as exacting a performance hit.
If I simulate pushToViewController by calling pushViewController twice consecutively, with animated:NO for the intervening view and with the intervening view set temporarily to be transparent, will I get reasonable performance? Or, when the nav mode is requested, should I place the nav controller's stack behind the isolated views, do the multiple calls to pushViewController, and then move the nav controller to the front? Or should I forgo the use of UINavigationController altogether and do all the table-view-style navigation manually via UIView’s add/remove/insert/exchangeSubview?
I believe setViewControllers:animated: is going to help you do what you want.
When you want to add several view controllers to the stack and directly go to the last one, you can explicitly set the entire stack and have the UINavigationController animate navigation directly to the last one.
NSMutableArray* controllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
[controllers addObject:newController1];
[controllers addObject:newController2];
[self.navigationController setViewControllers:controllers animated:YES];
This will push newController1 and newController2 to your view stack and animate a transition to newController2.

UITarBarController / UINavigationController Hybrid

Quite possibly I'm missing something obvious, but I have a very simple requirement and neither of these two seems to meet it.
I have an application with 3 distinct views, however for reasons I won't go into here (essentially views may or may not be valid depending in what is done in other views), using persistant tabs as navigation will not work. I also want each view to be created as needed and UITabBarController creates all its views upfront. However I still want some of the functionality of UITabBarController - being able to pass it in an Array of UIViewControllers.
UINavigationController offers the chance to have it create its views as needed, but there is no way for me to pass a list of views to it up front, so I end up with ViewControllers creating and pushing other (sibling) ViewControllers which is nasty.
So here are my requirements:
I want to be able to add ViewControllers upfront
I want to be able to navigate between the view controllers
I want each ViewController to be created as needed and destroyed when navigated away from
Is there anything that fits the bill?
I would use the AppDelegate to create a hash of viewcontrollers upfront and create a navigation controller.
Once you click the button to navigate to a new viewcontroller you can go to the hash and look for that specific view controller. If it is not created you can create it there. If you want to destroy that view controller just release it and remove from the hash.

pushViewController and Navigation Applications?

Why do Navigation Applications use pushViewController instead of presentModalViewController like all the other apps? How can a Navigation Application be modified to use presentModalViewController instead? Would it be sub-optimal to do so? Why?
Navigation view controllers and modal view controllers are there for different purposes. The first is used for display hierarchical nested contents. While you request more detailed info about an item, you go deeper in the hierarch pushing more detailed views over the stack.
The modal view is there for displaing only one view over the current. Its usefull for stuff like an info button for your app.
Your question is a little bit like asking why UISplitViewControllers use two controllers and lay their views out side-by-side. That is, UINavigationControllers use pushViewController: to manage their stack of UIViewController instances because that's how Apple decided UINavigationControllers should work. When animated into view, pushed views will slide in from the right and old views slide in from the left when a view is popped.
ANY instance of a UIViewController can use presentModalViewController to display the view of another UIViewController over top of it's own view in a manner which prevents the user from interacting with the view underneath. Depending on the device (iPhone, iPad) you have various options for the visual appearance of the newly presented view and the animation used to bring it into view.
There's nothing stopping you from writing an application that just keeps having one view bring up the next view using presentModalViewController but there'd be no reason to use a UINavigationController to do so. I've never checked if there was a meaningful difference in memory consumption or any other thing you could measure to judge whether doing so is "sub-optimal" from a technical perspective, but it's certainly not the norm so might be sub-optimal from the user experience perspective. Whether that is true or not for your app depends on whether users seem to think the interaction makes sense to them.
Navigation view controllers uses the concept of Stack.Your navigation is stored in stack that's why you can push & pop the View which shows that you can use them for the detail view ....making a hierarchy of views
whereas modal view controllers shows only one view at a time......this is generally used for new flow in app.

Are modal view controllers the preferred way to replace the entire interface on an iPad?

Specifically, I have something like a game, with a menu screen made out of standard components. I want a button to switch to another view controller that the user will interact with for a while, then return to the menu screen. It seems like having the menu controller present the 'game' mode as a modal view controller is the most straightforward solution, but is this the best way to essentially replace the entire view? Is the whole menu (which may later become a deep nav or split controller) kept in memory as long as the modal controller is in front, and is this something I should bother to worry about?
There are really two parts to this question:
Which method of transitioning from one view to the next in an iPad application provides the best experience to the user?
Which method of transitioning from one view to the next is easiest to implement and best handles memory management?
I'm not going to try to address the first part of this question other than to point you to Apple's 'iPad Human Interface Guidelines' which says (among other things):
Reduce Full-Screen Transitions
Closely associate visual transitions with the content that’s changing. Instead of swapping in a whole new screen when some embedded information changes, try to update only the areas of the user interface that need it. As a general rule, prefer transitioning individual views and objects, not the screen. In most cases, flipping the entire screen is not recommended.
When you perform fewer full-screen transitions, your application 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.
http://developer.apple.com/library/ios/prerelease/#documentation/General/Conceptual/iPadHIG/DesignGuidelines/DesignGuidelines.html
However, in your case I'd have thought a full-screen transition is entirely appropriate (but then I'm not a user experience expert).
In answer to the second part, yes displaying a new view controller modally seems like a good approach to take.
By default both the objects used by the menu view and those used by the modal view will be kept in memory - but the great thing about using UIViewController sub-classes is that they've got some default memory management built-in. If your application receives a memory warning whilst the modal view is being presented in full-screen mode, the menu view controller's views will be removed and it's 'viewDidUnload' method will be called. So in your implementation of this method you should release any objects you don't need and then recreate them as needed in the menu view controller's viewDidLoad method (which will be called again before the menu view is shown).
This is explained in more detail in the UIViewController class reference:
When a low-memory warning occurs, the UIViewController class purges its views if it knows it can reload or recreate them again later. If this happens, it also calls the viewDidUnload method to give your code a chance to relinquish ownership of any objects that are associated with your view hierarchy, including objects loaded with the nib file, objects created in your viewDidLoad method, and objects created lazily at runtime and added to the view hierarchy. Typically, if your view controller contains outlets (properties or raw variables that contain the IBOutlet keyword), you should use the viewDidUnload method to relinquish ownership of those outlets or any other view-related data that you no longer need.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html