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.
Related
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)
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
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.
I have two different view controllers. One is programmatically created(slideshow) and the other is with the interface builder(Login page). On the slideshow, once the user reaches the last page, it should perform segue to the login page.
How can I make this work?
First you can't create a segue between a VC created in code and another created in IB ( as both should be in IB ) , you must present it like this
let login = self.storyboard?.instantiateViewController(withIdentifier: "loginID") as! loginViewController
and use
self.present(login, animated: true, completion: nil)
OR use this to completely clear the stack of shown VCs
UIApplication.shared.keyWindow?.rootViewController = login
If two view controller don't need to transmit data, you can just change window root view controller to login page. Of course, with animation would be better.
I have a navigation controller stack with different possible controllers in it.
I want to present a view controller modally as and when I need it based on the next view I am pushing in to navigation controller. (You can think of that as user login validation screen..which validates user before moving to next screen.)
I am able to do it successfully with
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(contactPicker, animated: true, completion: nil)
and dismiss it when I need to dismiss with
UIApplication.sharedApplication().keyWindow?.rootViewController?.dismissViewControllerAnimated(false, completion: {
self.navigationController.pushViewController(myNewVC, animated: true)
})
I am able to do it however the transition from modally presented view to my (myNewvC) new push for next view is not exactly how i want it to be. When view dismiss happen I can see my caller screen for a second before i move to next view. I don't want to see that screen. Is it possible?
(Also I don't want to add validation screen in navigation stack as purpose of that screen is not to be part of navigation stack).
The completion block is exactly added here by Apple to protect you from uncaught exceptions because what you want to do might result in one, cause you can't do two animations at the same time, maybe some suggested solutions:
Try to present the new controller then when it's done hide the previous one in the completion block (this way when the user dismisses the new controller, he won't see the previous one), e.g.
Assuming you are in VC1 one now and you want to dismiss it and show VC2, you can use the below code in objective-c
[self presentViewController:VC2 animated:YES completion:^{
[self dismissViewControllerAnimated:YES completion:nil];
}];
In swift
self.presentViewController(VC2, animated: true) { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}
Or you can just ignore it if the user won't dismiss the new controller, then he would never see the old one but I don't think this is memory-efficient because the controller would be stuck in memory.
I didn't try it myself but if you use UINavigationViewController and you just don't want to go back that ViewController, than you can simple remove from stack after you go to the next ViewController.
In here you can see how you can change the UINavigationViewController's ViewController array:
Removing viewcontrollers from navigation stack