Can someone explain UINavigationController setViewController and popToViewController - iphone

I'm familiar with the idea of creating a new viewcontroller and pushing it onto the stack. So far I have just created an instance of my view controller and pushed it. Now I am running into a problem that my 3 different view controllers are related ways of looking at the data. My RootViewController has 3 icons to start, and when you press on an icon, you push the first view controller. I currently do not set the view controllers in an array since I'm not sure what that buys me or how that works.
Scenario 1: Click on icon 1 (push vc1), click on a table in a popover in vc1, it'll push to vc3. Then you click on something in vc3, and it'll go to vc1.
Scenario 2: Click on icon 3 (push vc3), click on something and go to vc1.
So the problem I'm having is in scenario 1, it would seem to make the most sense to pop back to vc1 so they don't have a stack of vc1/vc3/vc1 and are looking at the data twice like that. But in scenario 2, since I started at vc3 instd of vc1, I should push vc1. But in both scenarios, the user is clicking on the same thing to go to vc1 from vc3, so how do I tell which viewController they came from in order to push or pop to vc1?
So I guess that's where I thought setViewControllers or popToViewController might come in handy, but I'm not sure how those work and if there's some simple example snippet someone can provide to get me started (assuming this approach is ok). Thanks!

It sounds to me, from your description, that you should be using a navigation controller that you push and pop onto and off. Btw, the navigation bar doesn't have to be visible.
It also sounds like you should sometimes pop the current vc before pushing the next vc. You will need to check the count of the viewControllers array - if the current count is greater than one then pop before pushing, otherwise just push as you are at the root view controller.
Or, you could use popToRootViewControllerAnimated:NO each time before pushing.

UINavigationController is what allows you to manage your views.
setViewController allows you to set which controller handles your view.
popToViewController takes the current view controller off the stack to the specified view.
IMO... The last 2 promote spaghetti logic and should be used sparingly.

Related

Move Between different Navigation Controllers in Xcode Swift

I want to move from one UINavigatioController to other UINavigatioController. Scenario is First I am at ContactVC and after pressing any cell I will be move to ChatVC. Now when I press the back button on chatVC I want to move back on InboxVC. How can I achieve this scenario.
A UINavigationController is a stack based navigation system. This means when you navigate forwards you simply add another UIViewController to the stack, and when you navigate backwards you pop a UIViewContrller off the stack.
To do what you are proposing you will need to change the underlying UIViewController's that are currently in the navigation stack. You can do this by using func setViewControllers(_ viewControllers: [UIViewController], animated: Bool) on UINavigationController programatically, but you can't do it through a storyboard as thats not how a UINavigationController is intended to be used.
UINavigationController controller keeps a stack of the views (in simple words to understand) when a push a new view controller onto it. So when you press back it essentially pops the last view controller to display its parent controller. This is also normal user behaviour on the iOS platform.
The behaviour you are looking in counter-intuitive to the user since you are breaking their flow of navigation. But if you can a have a strong case for it. You can manually create a back button which can push to the inbox controller to get this sort of behaviour in code or in interface builder.
Another way to achieve this perhaps what you can see in other apps is:
you have a Signup view controller (which might be the form). When the signup is completed.
change the root view controller of the window to Inbox controller and
The same time, push the Chat controller so when your user pushes the back button, they will be taken back to the Inbox.

Navigation Controller design for multiple duplicate views

I'm having a hard time understanding what approach I should take. I have a TableView controller with a list of questions, if you click a row it pushes a new QuestionViewVontroller that displays the question, answers, and next button (or done button). When a user clicks next I want to load the next question (from the tableview list) but I still want the navigation to work (back button will take you to TableView).
I'm starting to think I should keep the same QuestionViewController and just load in the question data. Is this right? Or should I use a modal view?
You have a couple of options here.
Use the same QuestionViewController and just repopulate it, like you mentioned.
Push a new QuestionViewController and use custom back button that either pops to the root view controller or pops to a given view controller.
The code for both options in #2 is below, where "self" is the current view controller (your question controller).
[self.navigationController popToRootViewControllerAnimated:YES]; //this would pop to your UITableViewController, assuming it was the root
[self.navigationController popToViewController:yourTableViewControllerHere Animated:YES]; //this would work as long as you passed a reference to your UITableViewController to your question controllers
It's up to you how you choose to solve your issue. However, if you decide to use the same QuestionViewController, include a catchy animation when importing the new question so the user knows what is happening and to make your app that much cooler :)

view controllers using storyboard

i am trying to switch between two view controllers using storyboard. I create a modal seague by control-dragging (on buttons) from 1st view controller to 2nd, and then from the 2nd to the first.
So whenever I click on a button in 1st VC, it takes me to the 2nd VC. This time when i click the button on second VC, does it take me back to the original instance of the 1st VC or it creates a new instance?
If it takes me to the same instance, and user had written some data in some textfields, is there anyway to retain that on screen? (I might want to save them in some variables, and since the program will return back to the same instancem i'll be able to get the variables back)
If it doesn't take me to the same instance, is there any method to do so?
I tried making an instance of 2nd VC and using self.navigarionController push...(instance) but this doesn't swtich the controller.
If i do this pushing using the storyboard, and i do pop in my 2nd VC, it doesn't get popped either.
(and i would also couldn't understand the difference between push,modal and custom seagues)
Create the modal segue from VC1's button to VC2, but not the reverse one. When the VC2's button is tapped, call dismissViewControllerAnimated:completion: to return to where you were.
If you used a push segue instead, you would call popViewControllerAnimated: to go back but that only works if you have your view controllers managed by a UINavigationController.
You can think of push as a way of stepping through a sequence of related scenes while modal is something that's a bit out of the normal flow of the application. (That's not a firm rule but it's a starting point for deciding which way to go.) For 'custom', you write the segue code, so you decide what happens.

Pushing a new viewcontroller via a next button?

Sorry I can't show code for this question - it should be fairly simple to explain..
I have an array of data (object1, object2, object3, etc)… I have one tableview that lists these objects (object1.title, object2.title, etc) and upon clicking it push's a viewcontroller that shows the detail of each object. Now, rather than have to press Back on each detail view, I'd like to put a next button on the detail page..
I could easily push a new controller, however it would end with a chain of:
List View -> Detailview1 -> Detailview2, etc..
which would be a pain to traverse back up the stack.. Can the parent view controller be removed / changed easily or is this not the best way to do it?
Cheers.
You can always pop back to a specific index in the stack. So you could have a back button that pops back to the parent. If there is no real reason that the user would need to go back through the detail view controllers you could swap controllers by replacing the stack with a new stack using setViewControllers:animated: Look through the UINavigationController documentation and see whats possible.
This code will "pop" the view contoller off the view, so it removes it, instead of overlaying another view on top of it. Add this to your button action
[self.navigationController popViewControllerAnimated:YES];

UINavigationController strategy (iPhone)

Something is puzzling me, after going through my app with instruments, it is a UINavigationBased App, it noticed this.
Each time a tableView cell is tapped and I do this:
GenericTableViewController *someViewController = [[Generic TableViewController alloc] init];
[self.navigationController pushViewController:someViewController animated:YES];
[someViewController release];
I then tap the back button and look in Instruments to see how many living instances of the GenericTableViewController there exists. There is 1 before the back tap, and 0 afterwards.
This is great, good clean memory management by the UINavigationController.
However, other places in the app I don't use the back button to leave a view, in some viewControllers tapping one of my custom buttons will run code completely like the above, but the viewController, in which I tapped the custom button, will not be released.
I guess I understand why, the navigationController makes a judgment call, that I might be pushing something on to the stack and that I will return later, so it keeps the controller in its memory. This must mean that tapping the back button uses a [self.navigationController popViewController]. Ok.
The problem is now that each time I visit a view that isn't left using a "back" button in the navigationBar, it
will not be released. The count allocation in Instruments just goes up each time I visit a view, until I have like 20 objects living.
I tried putting a [self.navigationController popViewController] in the selector for my custom buttons. Meaning that I manually pop the visible viewController before pushing a new on to the stack.
But the allocation count does not go down? guess the "back" button does not use this technic after all...
I also tried using popToViewController, since I always know if the controller has been on the stack or not. But to use the popToViewController, I need to keep a reference around for the view.
Is there some sound way of saying to the UINavigationController: If this viewController is on your stack, please display it, if not please instantiate it, push to the stack and display it.
The challenge here is probably that not all my navigation in the NavigationController is completely linear. I will sometimes have to go from stack item no. 2 to stack item no. 5, back to 3 etc.
So is there a way to do this, while still having the UINavigationController making sure to release my viewControllers and not instantiating the same viewController several times?
You could try to access UINavigationController's viewControllers property to get a NSArray of all the view controllers currently on the navigation stack. Then use containsObject: to check if the view controller is already on the stack.
If it is, then use popToViewController:animated: to show the view controller. If it is not on the stack then just use pushViewController:animated:.
If this does not help you, maybe setViewControllers:animated: is the right method.