difference between presentViewController and UINavigationController? - ios

Please tell the difference between presentViewController and UiNavigationController? Could I use presentViewController instead of UINavigationController to navigate different views in the app?
Whats the scenario to use either?

presentViewController offers a mechanism to display a so-called modal view controller; i.e., a view controller that will take full control of your UI by being superimposed on top of a presenting controller.
UINavigationController offers a much more flexible mechanism where you can push a new controller, and later pop it, so to go back to the previous one, in a ordered way. Imagine that controllers in a navigation controller will just build a sequence from left to right.
I think that presentViewController is most suitable for use with just one view controller being presented at a time. You can surely use it to stack more view controllers one on top of the other (and thus sort of "mimic" a poor-man's navigation controller), but my bet is you will quickly find something not working as you expected.
Specifically, an example of such limitation is the following: when you dismiss a modal view controller (in order to "close" it), all of your modally presented view controllers (from the same presenting controller) will also be dismissed at once. So you simply will not be able to implement a "go back"/navigation like functionality.
So, it depends on what you are trying to do.

A UINavigationController is a subclass of UIViewController that manages a stack of view controllers and adds a back button etc.
presentViewController is a method of the UIViewController class you use to present a modal view controller.

The UINavigationController maintains a navigation stack for you. You are then able to navigate through hierarchical content.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
If you use UIViewControllers presentViewController method you are basically just replacing the view controller. no navigation stack is maintained for you.

UINavigationController is a class, presentViewController is an instance method of UIViewController (iOS 5 + ), of which UINavigationController is a subclass.
pushViewController is a comparable method to presentViewController. It is an instance method of UINavigationController, for iOS 2 +

Related

Is it possible to segue from a modal view to a view that is not in the hierarchy on a Navigation Controller in swift?

On my main view in a NavigationController I have a button that brings up a new view modally to submit a post. I have a button to dismiss this view which brings the user back to the main view, however if the users proceeds to make a post, I want it to dismiss the view and proceed to a show the post in the Navigation controller.
The ideal effect would have the standard navigation controller's back button on the top that can bring the user back to the main view when they have finished looking at their post.
I have tried several different methods, but I tend to get an error stating "Warning: Attempt to present (The View I Want to Show) whose view is not in the window hierarchy!
Thanks for any info!
Yes, it's possible. This is the best way I've found to structure the app to allow this functionality.
RootViewController
UINavigationViewController
ContentViewController (your current "main" view controller)
You're basically going to create a new RootViewController that is going to contain your current UINavigationController as a child. I usually setup the window.rootViewController programmatically in the AppDelegate. I would also keep a global reference to it.
Have a look at Apple's documentation on this. Basically, the RootViewController code would look like this:
[self addChildViewController:navController];
navController.view.frame = self.view.bounds
[self.view addSubview:self.navController.view];
[navController didMoveToParentViewController:self];
Now, whenever you need to present a modal view controller, present it from the RootViewController, instead of the current/top view controller on the UINavigationBar. This allows you to manipulate the UINavigtaionController independently and you won't get the error you're seeing.
So present the modal view controller from the RootViewController, this covers the UINavigationController and its content (top view controller). Make any changes you need to the UINavigationController stack (push, pop, etc...) with no animation. When you're done dismiss the modal view controller (with animation) and it will show you're adjusted UINavigationController.
Hopefully, this all makes sense. It's kind of complex and hard to explain in text. :p
If you don't want to setup a RootViewController, you might want to try presenting the modal view controller from the UINavigationController, as that might have the same effect. From the view controller just do self.parentViewController.present.
The main thing you're trying to avoid is presenting a modal from a view controller and then removing that view controller (pop) before the modal is dismissed. The view controller that presents the view controller is responsible for dismissing it.
I finally got it all working (I'm still new to Swift) and the two comments on the question were very helpful. The most helpful of all was the top answer here's example on github.
Similar question

UINavigationController vs viewController embed in NavigationController

I was trying my hands on iOS and while building apps, one question get into mind that what is the difference between UINavigationController vs viewController embed in NavigationController.
While using UINavigationController we push and pop views.
while using viewController we present and dismiss.
SO what are the applications where one is more superior to use than the other.
UINavigationController is used where you want you move back and forth in your application. Generally Navigation controller is used when you are navigating in more detailed information in each level of depth you are in your application.
UIViewController is generally preferred when you display polished information. in UINavigationController generally it is the one of the last controller you push in your controller
I think you are really describing two sides to the same coin. There is only one way to use a UINavigationViewContorller. It is a known as a container view controller and its job is to push and pop other UIViewControllers. A UINavigationViewController works with viewControllers, not views.
UINavigationController:
If you have hierarchy of view controller then that is you have stack of view then you need to use navigation controller. You can perfrom push and pop operations on the view controller and Navigation Controller is the rootViewController of all ViewController.so to go back to the previous one, in a ordered way. Imagine that controllers in a navigation controller will just build a sequence from left to right.
UIViewController: if you are using view controller it act as presentViewController. The presentViewController offers a mechanism to display a so-called modal view controller; i.e., a view controller that will take full control of your UI by being superimposed on top of a presenting controller. I think that presentViewController is most suitable for use with just one view controller being presented at a time. So you simply will not be able to implement a "go back"/navigation like functionality.
UINavigationController inherits from UIViewController. The strange thing about this object model is the UIViewController has a property called NavigationController. So for OO purists this is a bit baffling that a parent class knows about its children. But moaning aside this is how it’s been done in UIKit. As you’ll find with a runtime error, you can’t place a UINavigationController inside a UINavigationController
Whenever you push a controller, it can access the parent UINavigationController it may or may not belong to via the NavigationController property. The property is null if the controller is not inside a UINavigationController.

What are limitations of presentViewController over UINavigationController

I am confused about "In which situations we have to use presentViewController and UINavigationController".
I had read so many documents, but I haven't found accurate explanation. We can always use UInavigationController then what is the use of presentViewController ?
Thanks.
UINavigationController maintains the stack of the controllers that are being viewed. So once you push through 1->2->3 view controllers then you can pop in 3->2->1 manner. Unless you don't change the stack this kind of flow is maintained by UINavigationController. Now lets say you want to show 4th view controller without disturbing the above flow. Then you can use presentViewController.
This is the simplest and basic is for using navigation controller and presentViewController
You can't push a navigation controller into other navigation controller.
You can present a navigation controller above other navigation controller.
If you push a view controller into the navigation controller, view controller's view cover only area inside navigation controller.
If you present a view controller, view controller's view cover the window hierarchy (user can't interact with other parts of the application).
You can don't use UINavigationController to present some UIViewController. You should care about "close" button to let user to close presented UIViewController
I've create test project to illustrate my answer https://github.com/K-Be/PresentTest

Use of differenct view controllers

i'm curious about what's the best way to plan the controllers for my app.
i want my main screen to have 3 button.
1) should open a nav controller with details view
2) should open a controller with other buttons that lead to others controllers
3) should open a tab bar with 2 pages ( or eventually use a switch to change page instead of the tab bar)
this is the schema of what i want
http://i59.tinypic.com/2rrvrd4.png
Is it a correct schema or i should use my controllers differently? will apple reject an apple with such schema?
thanks
As #Fogmeister pointed out in the comments, going for a UITabBarController as the main interface for your app actually seems to be a more appropriate solution here.
However, you can go with the interface that you described, but then you should keep in mind that with your current setup, you are not only using UINavigationController in the first case, but your whole navigation system is still built upon UINavigationController in the following way:
Your app has one instance of UINavigationController.
Your initial UIViewController (the one with the three buttons), is the rootViewController of your UINavigationController.
You can navigate to the other view controllers using [self.navigationController pushViewController:newViewController] (or performSegue if you prefer using Storyboards).
In the case of your third view controller, you are pushing a UITabBarController onto the navigation controller's view controller stack, this UITabBarController needs to be initialized with the two view controllers that it is going to display before it gets pushed onto the stack.

Adding Popover to current Navigation Controller hierarchy

I've seen a lot of other questions on here about adding a UINavigationBar to a UIPopoverController. All of the examples I've seen follow one of two patterns:
In the init or viewDidLoad method of the Popover subclass, you alloc-init a UINavigationBar directly, as suggested here. This method is a little hacky, and while it shows up nicely, if the popover is a UITableViewController, you have to mess with a bunch of things to make sure the navigation bar you just added doesn't overlap one of your cells.
Alternatively, a lot of post suggest creating a UINavigationController just before presenting the popover, as shown here.
With the second method, however, won't the popover be the only controller in the newly created navigation controller? And if my view that I'm presenting the popover from is itself already in a navigation controller, the popover will NOT be in that same navigation controller, correct? It seems to be that the more appropriate thing to do would be to add the popover being created as another controller in the navigation controller that already exists (and which the controller that presents the popover is already a part of). Is that possible? Or is there a reason why the navigation controller for the popover needs to be independent from the navigation controller for the presenting controller? Or am I totally missing something here?
You have many questions, young Skywalker. :)
Creating a UINavigationController and then embedding the controller you would like to present is the way to go.
Don't get confused by all the controllers involved here:
UIPopoverController is a construct that shows an existing UIViewController in an overlay like style. UIPopoverController itself even isn't a subclass of UIViewController. The name is misleading.
So UIPopoverController hosts another controller. In your case, we let it host a UINavigationController.
UINavigationController is a subclass of UIViewController. It is a container controller and can handle a stack of UIViewControllers.
On that stack we push one UIViewController: the one you want to display and garnish with a UINavigationBar. Since Mr. UINavigationController comes with a build in UINavigationBar, he's our friend.
There is no need to subclass UIPopoverController. You just keep one static reference to it around so you can dismiss the current open popover in case you want to present another.
It does not matter where you present the UIPopoverController from. It will always be a popover. Even if presented from an existing UINavigationController. Only if you use presentViewController: you will get different results depending on the controller you're presenting from (modal or pushed on top of the stack).
won't the popover be the only controller in the newly created navigation controller?
No, the popover will contain the navigation controller and the navigation controller will only contain its root view controller (which would otherwise have been added directly to the popover as its root).
You seem to be a little confused about the relationship between the popover and the popover root view controller...
the popover will NOT be in that same navigation controller, correct
Yes, correct. The popover is effectively a window floating above all other views
Or am I totally missing something here?
Maybe... The popover would usually be used for displaying something modal, transient and smaller than full screen size. Putting a navigation controller in the popover and adding views to it is the normal approach.
Adding a navigation bar to a popover isn't hacky. A navigation bar is just another regular view. That also means that using a UITableViewController with it, the navigation bar will overlap the table view, as the UITableViewController's view property just returns the controller's tableView property. If you want to add a navigation bar above a table view, without it overlapping the table view, use a regular UIViewController and add your navigation bar and table view the normal way. UITableViewController should only be used if your only view within that view controller is a table view.
Having said that, I do agree with others that just using a navigation controller without using its navigation features is the most common approach.

Resources