pushViewController and Navigation Applications? - objective-c

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.

Related

UISplitViewController - Multiple Detail View Controllers via storyboard segues

I'm trying to do a project for the iPad in which I'd like to utilized the split view controller. I'll be having different detail view controllers for each of the cells in the master view controller.
I saw one solution how to do this via storyboard segues in this site.
He basically linked each of his UITableViewCell to different detail view controllers. But I'd like to know if this is a "stable" or a "good" way of doing this. I mean, is it any better or as stable as doing it programmatically? What would be the consequences of doing his method, if there are any?
Here is the link to the solution I found
This is kind of a tricky one, even though it's an incredibly common use case.
1) One idea is to have an empty root view controller as your detail and it handles managing segues under the hood to quickly segue to the detail view you actually care about, utilizing the "replace" segue. This should "technically" fix having the "back" button at the top left and still allow you to pop to root and not have it show the empty controller. Haven't tested these though, so I'm not sure.
Edit: In Xcode 6, the "replace" segue is conveniently handled by a "show detail" segue which is used specifically for this type of view handling on Split View Controllers. I recommend using this method exclusively in new projects. See sample code.
2) The other idea is to have separate navigation controllers in your storyboard (one connected, the rest all stranded). One for each detail view type and tapping on the master menu will simply swap the navigation controller for the detail view to the one you care about.
Code similar to this in AppDelegate:
self.detailNavigationController = [self.masterNavigationController.storyboard instantiateViewControllerWithIdentifier:#"MyChosenNavigationControllerStoryboardId"];
self.splitViewController.viewControllers = #[self.splitViewController.viewControllers[0], self.detailNavigationController];
self.splitViewController.delegate = (id)self.detailNavigationController.topViewController;
The downside to this second way is that in memory tests, it doesn't appear that swapping a new nav controllers in frees up all of the memory that the old nav controller was using. So it's good to use for simple apps but not for anything crazy complex.

IOS menu/design

Relevant Data:
I'm making a simple game, using OpenglES. The game itself is done, however I would like to have a main menu as well as some other screens designed in IB. So far I have a death/score screen that is displayed with a simple modelviewcontroller.
I haven't done a ton with GUI building or much programming on the platform outside of C code (posix sockets) and some examples from some books. So I'm not sure how I would go about having lots of views- usually I just use a model view, and it's gotten me along just fine so far. However I don't think that would be the best route here.
Situation:
I have a view controller that shows my main menu- the main menu branches off to the main game, a settings screen, and a high score screen. The main game is made in opengl, and I haven't made the settings view yet, but it likely will be as well. How should I switch between the views? Presenting the main view from the app delegate is as simple as setting the root view controller = newly created view controller, should I do the same thing here? If I do that can I remove the resources from the menu view controller?
Sorry if this is an extremely simple question, I just don't quite get the process.
I'm not entirely sure what you want to do, but an easy way to show a new view controller is:
SecondViewController *aSecondViewController = [[SecondViewController alloc]
initWithNibName:#"SecondView" bundle:nil];
[self presentModalViewController:aSecondViewController animated:YES];
I hope that helps.
How should I switch between the views?
In the vast majority of cases, you should be using a UINavigationController. Your initial controller would be the main menu. When you want to go into a particular section of your application, you push a new view controller onto the stack. When you want to come back out, you pop it off the stack.
Besides navigation and presenting modally that others have mentioned, another option is to swap out views. May or may not fit your app's flow but wanted to point out another option for you to consider
Best practice for switching iPhone views?
If you are already limiting the game to iOS 5 for some other reason you should look into UIStoryboard. If you don't currently require iOS5 the "simplest" way is to use table views, but that isn't a very "gamey" UI.

How do I add UITabBarController subview to UINavigationController

I am new to Objective-C and Cocoa and I am trying my way through some tutorials with some success. One task is troubling me. I am trying to create a root view controller that is a navigation controller as given by this tutorial:
http://fuelyourcoding.com/iphone-view-switching-tutorial/
On the second page that is pushed I would like the option to load a subview that is a TabBarController. Is this within iOS view guidelines. Is this possible? If so, could someone give some code snippets and explain necessary instantiations and connections in IB? Your help is appreciated in advance!
No, you should not push a UITabBarController to a UINavigationController stack.
Perhaps tell us what you're trying to accomplish and someone can suggest an alternative.
From Apple's View Controller Programming Guide - Tab Bar Controllers:
Note: Although a navigation controller
can be embedded inside a tab, the
reverse is not true. Presenting a tab
bar interface from within a navigation
interface is potentially confusing for
users. A navigation interface uses one
or more custom view controllers to
present an interface focused on one
goal, which is usually the management
of a specific type of data. By
contrast, the tabs of a tab bar
interface can reflect completely
different purposes in an application
and need not be related in any way. In
addition, pushing a tab bar controller
on a navigation stack would cause the
tabs to be displayed for that screen
only and not for any others.
I cannot answer your question directly, but in my app I have a UITabBarController which displays multiple UINavigationControllers and other types of controllers. So I think you may have it the wrong way around. In other words, create a project which uses a UITabbarController as the base controller and when you select a tab, load up the corresponding UINavigationController (or other type of controller) as necessary.

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

"Infinite Drill-down" with UINavigationController

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