How can I go dismiss two viewcontrollers with navigation controller? - ios

I have three relevant views, they are all connected to a navigation controller, with push segues (also I have stored arrays using prepare for segue with all three). So I want to use dismiss since I don't want to change the already existing stored arrays that are used in the viewcontrollers.
So I'm at viewcontroller C , and im trying to go back to A.
I have until this point used self.dismiss(animated: true, completion: nil) which works great when dismissing to view B, but I want to go to A.
I have also tried using:
let presentingViewController = self.presentingViewController
presentingViewController?.presentingViewController?.presentingViewController?.dismiss(animated: false, completion: nil)
However this does not work, and produce this error:
pushViewController:animated: called on while an existing transition or presentation is occurring; the navigation stack will not be updated.
Any solution to this?
The reason I want to go to viewcontroller A is because there is a bug in Viewcontroller B when something is updated on Viewcontroller C, so a temporary solution is to just go to A, and reload the tableview.

Call setViewControllers(_:animated:) on the navigation controller, passing in an array containing only view controller A. As view controller A is already in the stack, the animation will be a pop.
Alternatively, if you’d rather use segue’s, you can perform an unwind segue, back to view controller A.

Related

dismiss more than one View Controllers to return to the root ViewController in ios13

I have three view controllers written programmatically, the first VC is Sign in but if the user forgets the password this will led him to another two view controllers I need to return to the sign in VC directly form the third VC after the user finish the specific procedures.
you could do like this
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
since are both vc to dissmiss it will return to login vc.
every presented viewController has a property called
PD: presentingViewController, is hold as reference to the viewController that is responsable for present it, so 2dn VC has a reference to 1st VC as presentpingviewcontroller, but also 3er VC have a reference to 2dn vc that has a reference to 1st VC so you call the above method chaining two presenting and ending in first VC, so you could present as many VC as you want as long as you know how many have been presented you could return to what ever you want.
You can use navigation controller, push your view controllers to navigation like
self.navigationController?.pushViewController(viewController: vc, animated: true)
and when you need to close all controllers use
self.navigationController?.popToRootViewController(animated: true)

Save all subsequent view controller states in UINavigationViewController

I have a container UIViewController that hosts a single UINavigationController. The container view controller has a button that opens a new view controller by calling present(newViewController, animated: true, completion: nil).
The newViewController has its own UINavigationController and also contains a button. That button can present another view controller that itself has a UINavigationController and another button and so on.
I want to keep that pattern going for as many iterations as possible and save the states of all of them. Is that possible? To close the current view controller I call _ = navigationController?.popViewController(animated: true) but that erases all the data from the previous view controller as well.
You asked two questions
1) want to keep that pattern going for as many iterations as possible and save the states of all of them.
Ans. : you can not continuously presenting view on already presented view controller. for that first you need to dismiss previous presented view.
2) To close the current view controller I call
_ = navigationController?.popViewController(animated: true)
but that erases all the data from the previous view controller as well.
Ans. If you present any view controller then don't use popviewcontroller but use dismisViewController.

How to access previous view controller from a dismiss command

Throughout my app I use a navigation controller to push and pop my view controllers. When I pop from one ViewController, I check to see if I can reload the data in the previous one with this:
_ = self.navigationController?.popViewController(animated: true)
if let previousViewController = self.navigationController?.viewControllers.last as? AnimalsVC {
previousViewController.tableView.reloadData()
}
This works every time, but now I need to do the same with another view, but it's not apart of the navigation controller because I modally present (instead of pushing it to the navigation controller). Now there's no way I can access the previous ViewController like before and I can not figure out how to access the previous ViewController.
How can I access the previous ViewController to reload the tableview like the example code without accessing the navigation controller?
I know this is possible with notifications, but I prefer not to use that method if possible!
First of all, It's not necessary to access the previous ViewController to reload tableview(or any other func)
I recommend you to use Delegate to achieve the same feature.
Holding a reference to the previous viewController in the way you mentioned will make your app very hard to maintain when your app gets more complicated.
You can call tableview.reloadData() in viewWillAppear method in the controller that you present modally

IOS Navigation Non Heiarchical

I have an iOS app using iOS 5 and Xcode 4.3.2 that is made up of 7 view controllers. VC1 links to VC2, VC2 can link to VC3-VC7 and each of those controllers can link to each other (think of it as a side bar navigation). If I use segues the views are repeatedly added to the stack and if a user goes back and forth it can use a large amount of memory. How can I implement this navigation where I release the previous controller? They are all small controllers so loading them takes little time/processor/memory. Can I presentViewController and then release the presentingViewController somehow? Thanks.
If you implement a UINavigationController, you can use the push and pop view controller methods to go back and forth. popToViewController:animated: is described here, along with 3 other helpful methods.
Well seems like there should be no problem from VC1 to VC2. For the VC3 - VC7 you could:
Present as modalViewController instead of pushing that to the stack.
Or:
- Use the popToViewController:animated: function of your UINavigationController if the Controller is already present in the stack of controllers, otherwise push it. Like
// Assuming u need to push VC6
for(UIViewController *controller in [urNavController viewControllers]){
if([controller isKindOfClass:[VC6 class]])
{
[urNavController popToViewController:controller animated:YES];
}
else{
VC6 *VC6controller = [[VC6 alloc] init];
[urNavController pushViewController:VC6controller];
}
}
You could use UINavigationController's - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated method to remove any view controllers below the topmost one. Since the navigation controller's viewControllers array is an immutable one, you could not use any NSMutableArray's removeObject... methods directly on the viewControllers array. You would have to make a mutableCopy into a mutable array, remove any (hidden) view controllers you wish to discard from the mutable array, and pass the resulting slimmed-down stack of view controllers to the above method. Since your topmost view controller would be unchanged, there would be no transition animation in your case (see discussion below), so you could also set the viewControllers property directly without bothering with the animated: argument.
From Apple's documentation:
Discussion
You can use this method to update or replace the current view controller stack without pushing or popping each controller explicitly. In addition, this method lets you update the set of controllers without animating the changes, which might be appropriate at launch time when you want to return the navigation controller to a previous state.
If animations are enabled, this method decides which type of transition to perform based on whether the last item in the items array is already in the navigation stack. If the view controller is currently in the stack, but is not the topmost item, this method uses a pop transition; if it is the topmost item, no transition is performed. If the view controller is not on the stack, this method uses a push transition. Only one transition is performed, but when that transition finishes, the entire contents of the stack are replaced with the new view controllers. For example, if controllers A, B, and C are on the stack and you set controllers D, A, and B, this method uses a pop transition and the resulting stack contains the controllers D, A, and B.

UIStoryboard popViewController

I'm using a UISegue in my application to automatically transition between viewcontrollers in my application. I'll call them A and B.
It worked as expected, however when I wanted to pop-back to the A from B, I attempted to call
[self.navigationController popViewController] however the B's navigationController property reports null.
As a second attempt I attempted to map a button, to a UISegue back to view controller A.
However this just creates a new ViewController.
As a work around, I ended up doing as a work around was to retrieve the B viewcontroller from the UIStoryboard and calling [A.navigationController pushViewController:B]
At which point, calling [B.navigationController popViewController] worked as expected.
This seems wrong, from a storyboard segue how can I return to the previous view controller?
I don't know about the class of your A and B controllers (whether UIViewController, UITableViewController or UINavigationController), but if you follow the following pattern, it should work.
In an empty storyboard, insert a UINavigationController. This will bring in two windows to the storyboard, linked with an arrow (a segue). The one on the right should be controller A.
In A, let's say, you add a button. The button will push B into the navigation stack.
Then, you add the second controller B, and drag from the button in controller A to controller B, and choose "push" from the popped menu.
If you only use a UIViewController (A) and push B, there is no navigationController to take care of popping.
Hope that help.

Resources