How to programmatically pop a view controller and present a new one - ios

What I am trying to do is present a viewController and when the user touches a button I want to call popViewController and then present a different viewController. But I cannot figure out how to do it.
Some of the things I have tried are call pop and then immediately call present, call present after a delay, pup the pop with a completion block and then in the completion block call present, as well as other ideas.
I think I am over complicating the whole thing, i believe their should be an easy way to do this.
Thanks for any help with this.
CLARIFICATION:
I do this on a touch:
if let vc = UIStoryboard(name: "Listing", bundle: nil).instantiateInitialViewController() as? ListingViewController
{
vc.listing = listing
vc.editListing = forEdit
vc.title = " "
self.navigationController?.pushViewController(vc, animated: true)
}
From that VC when the user touches a button I do this:
self.navigationController?.popViewController(animated: true)
When the VC goes away I want to do something like this:
if let vc = UIStoryboard(name: "CreateListing", bundle: nil).instantiateInitialViewController() as? NewCreateListingViewController
{
vc.bMakeSimiliar = makeSimiliar
vc.listing = listing
vc.editListing = editListing
vc.title = " "
self.navigationController?.pushViewController(vc, animated: true)
}
Basically my user is viewing the first controller which is a listing, from the listing VC he touches a button to add a new listing, so I want to dismiss the listing view controller and present him with the create listing view controller.
When I execute the above code to present the new VC nothing happens. I am doing this immediately after the popViewController.

You don't use pop to present next controller in stack. Pop actually navigates back from the current controller.
To perform what you're trying to achieve you need to call navigationController.pushViewController(viewController: UIViewController, animated: Bool) method.
In order to get back to some previous view controller you use:
navigationController.popViewController(animated: Bool)
In order to get to the root view controller you use:
navigationController.popToRootViewController(animated: Bool)
In order to get to some specific view controller in the stack you use:
popToViewController(viewController: UIViewController, animated: Bool)

Related

How To Remove The First ViewController In The Background?

I have two view controllers, first view controller and the second view controller, when the user segue from the first view controller to the second view controller, the first view controller still visible and sits behind the second view controller. The user can swipe the first view controller and see the entire first view controller and then they got stuck there. I noticed that this only happens after the launch of iOS 13.
performSegue(withIdentifier: "showSecond", sender: self)
Follow these two steps:
Click on the segue you created on the Storyboard
Go to Attributes Inspector
Set the Presentation to "Full Screen"
#Maysam is 100% right! But you can also do it programmatically through this:
// Go to next View Controller
#IBAction func nextTextVC(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nextInfo = storyboard.instantiateViewController(identifier: "socialOptionsIntroViewController")
self.navigationController?.pushViewController(nextInfo, animated: true)
}
There is a more detail thread could answer this question.
The follow solution from Pratik Sodha
let controller = UIViewController()
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .overCurrentContext
self.navigationController?.present(navigationController, animated: true, completion: nil)

back to initial view controller

As you can see i have an initial view controller with label in it "Initial ViewController". In this view controller i use below code to go to selected tab of Tab Bar Controller
let vc1 = sb.instantiateViewController(withIdentifier: "tabbar") as! UITabBarController
vc1.selectedIndex = selected
let controllers = [vc1]
navigationController!.setViewControllers(controllers, animated: true)
In my First View, there's a button "Present VC" which presents "Presented View".
let vc1 = sb.instantiateViewController(withIdentifier: "PresentedVC") as! PresentedVC
present(vc1, animated: true, completion: nil)
Now i want to go back from presented vc to root vc(Initial View Controller). I can do this with:
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstNavigationController") as! FirstNavigationController
UIApplication.shared.keyWindow?.rootViewController = viewController
but this instantiate Initial View Controller every time and views remain in memory. How can i go back to Initial View Controller without instantiating it?
PS: FirstNavigationController is initial Navigation Controller.
At the very beginning you remove the initial view controller by doing this:
navigationController!.setViewControllers(controllers, animated: true)
All the previous viewControllers are gone now and replaced with the tabbar controller and its children.
If you want to go back to the initial controller, you will have to push the tabbar onto the stack instead of replacing everything with it. E.g.
navigationController?.pushViewController(tabbarVc, animated: true)
First when you did this
navigationController!.setViewControllers(controllers, animated: true)
the initial VC is deallocated (if it has not a strong references)
to keep it you can use push , pop instead of setViewControllers but note it may cause memory issues if you have heavy processing in your app as it will remain in navigationController stack
You are missing the concept between "Presenting" or "Setting" View Controller & "Navigating" the View Controller. You will get the answer, once you understood the concept. Here, it is..
When you are setting the ViewController, you are completely replacing the stack container to the new view controller. the way you did it here:
navigationController!.setViewControllers(controllers, animated: true)
In this case, STACK holds the addresses of the latest set/presented ViewControllers that means previous whole ViewController vanished.
On the other hand, if you are navigating to other view controller by pushing it. you can go back to previous controller by simple popping the ViewController address from stack. or to next ViewController by pushing
e.g:
self.navigationController?.pushViewController(tabbarVc, animated: true)
self.navigationController?.popViewController(animated: true)
Summary:
If you push TabBarController then, only you will get InitialVC.
Now, in your case, you are setting the ViewController and hence, you are not getting InivtialVC. Try Pushing tabbarVC This will work.
navigationController?.pushViewController(tabbarVc, animated: true)

How to push two view controllers modally without seeing the first one

I want to present two view controllers in a row, without seeing the first one.
I want to be able to return from the second one to the first.
I have read this post, but the responses focus on using the navigation controller, while I want to present the second view controller modally.
The use case is: My initial VC check if the user is logged in, and presents the login VC if not.
If yes, it displays the main VC.
On logout, I should be able to unwind to the login VC.
A suitable solution would be presenting the second view controller first and only presenting the first one after the second one fully appeared.
InitialViewController
let secondVc = storyboard!.instantiateViewController(withIdentifier: "Second") as! SecondViewController
secondVc.initialVc = self
present(secondVc, animated: true)
SecondViewController
fileprivate var firstViewDidAppearTime = true
var initialVc: InitialViewController!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if firstViewDidAppearTime {
firstViewDidAppearTime = false
let firstVc = storyboard!.instantiateViewController(withIdentifier: "First")
initialVc.present(firstVc, animated: false)
}
}

Swipe Right to Dismiss ViewControlelr without using Storyboard Swift

How to dismiss any View Controller without using Storyboard ? and do I have to use UINavigationController to achieve this ? if not how then ?
if someone is still struggling to dissmiss on swipe (left,right,bottom,top)
i came across a very elegant and decent cocapod panslip
with a very simple usage
just call this method in viewDidLoad()
For viewController embedded in navigation Controller
let viewControllerVC = self.navigationController
viewControllerVC!.ps.enable(slipDirection: .leftToRight){
//anything you want to do after dissming
}
For Simple View Controller
let viewControllerVC = self
viewControllerVC!.ps.enable(slipDirection: .leftToRight){
//anything you want to do after dissming
}
For TableView embedded in View Controller
let viewControllerVC = self.YourTableview.parentContainerViewController()
viewControllerVC!.ps.enable(slipDirection: .leftToRight){
//anything you want to do after dissminn
}
The way to dismiss a view controller is to call a dismiss method on the presenting view controller. If you presented your child controller from a parent by calling self.present(_:animated:) then you can call self.dismiss(animated:). If you used a navigationController and called navigationController.push(_:animated:) then you need to tell the navigation controller to dismiss with navigationController.popViewController(animated:)
Method names might not be exact, but you should be able to figure it our with autocomplete.
If you want to swipe right is not a dismiss, but I think that what you want it to embed the UIViewController inside a UINavigationController.
For example:
if let vc = UIStoryboard(name: "YourStoryboard", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController {
let navigation = UINavigationController(rootViewController: vc)
navigationController?.pushViewController(vc, animated: true)
}

iOS Swift, returning to the same instance of a view controller

I have a problem, where I have two view controllers A and B. View controller B has a map, with a route draw on it. I can move back and forwards between the two view controllers at the moment, but the B view controller is reset every time it loads. I think this is because I am using segues and it is creating a new instance of a View controller every time.
I have tried using the following code to solve this issue, but it is still not working. The views load correctly, but view controller B is still being reset
#IBAction func mapButton(sender: AnyObject){
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
What am I doing wrong and how can I fix it? I want view controller B to stay in the memory along with the map and the route, so when a user returns he doesn't have to enter all of the information again.
You should create a variable in your class of type UIViewController and change your code to the following:
#IBAction func mapButton(sender: AnyObject){
if yourVariable == nil {
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
yourVariable = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
}
self.presentViewController(yourVariable, animated: true, completion: nil)
}
That way you create the viewController one time, save it and if you want to open it again present the previously created one.

Resources