Issue popToRootViewController when dismissing view controller - swift

On dismiss of a .formsheet I need to perform a poptoviewcontroller currently I am presenting the view controller by doing the following:
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "test") as! TestVC
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .formSheet
self.present(navigationController, animated: true, completion: nil)
Attempting to dismiss and popToRootViewController underneath is not working
self.navigationController?.dismiss(animated: true, completion: {
print("Dismissing")
self.navigationController?.popToRootViewController(animated: true)
})
The dismiss is working, but it does not popToRootViewController.

When you're accessing the navigationController in your completion, you're accessing the same navigationController you've just dismissed, and not the "root" one.
Here's one of the ways you can access the navigation controller you're interested in and pop to root from it:
let presentingVC = self.presentingViewController
self.navigationController?.dismiss(animated: true, completion: {
print("Dismissing")
presentingVC?.navigationController?.popToRootViewController(animated: true)
})

Related

Swift - How switch between storyboards with back button?

I'm in a storyboard and I need to go to another storyboard by tapping a button. Well, this I've already done, but I need to go back to previous storyboard. Here is my code:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
}
By tapping a button on my UITableViewCell (where I have a protocol), this function (goContact) is called and I switch to another storyboard (FAQ). But, how can I go back to main.storyboard?
I've already tried do this too:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
// self.navigationController?.pushViewController(vc, animated: true)
// self.present(vc, animated: true, completion: nil)
}
Use only storyboard property , it references to Main storyboard of the app or you can write it like let storyboard = UIStoryboard(name: "Main", bundle: nil)
To go back after push do
self.navigationController?.popViewController(animated: true)
You should push your new view controller onto the navigation controller using push, like in your commented-out code. That will cause the new view controller to have a back button, which will pop it for you without needing any extra code.

Swift 4 back button doesn't appear

I have problem... i have two ViewControllers and i use this code to pass from 1st VC to 2nd
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "EVSignInViewController") as! EVSignInViewController
self.present(newViewController, animated: true, completion: nil)
The problem is.. i want to display back button on 2nd VC. I already tried use Editor->Embed in-> Navigation controller on 1st VC. Also i use this
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.backBarButtonItem = UIBarButtonItem(title:"", style:.plain, target:nil, action:nil)
Presenting a ViewController will present it modally over the top of your current one. It doesn't actually push it onto the navigation controllers navigation stack.
You either need to push the view controller instead
self.navigationController?.pushViewController(newViewController, animated: true)
or wrap it in a navigation controller and then present it
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "EVSignInViewController") as! EVSignInViewController
let navigation = UINavigationController(rootViewController: newViewController)
self.present(navigation, animated: true, completion: nil)
Use this method for present 2nd VC.
self.navigationController?.pushViewController(newViewController, animated: true)
instead of this
self.present(newViewController, animated: true, completion: nil)
You will get back button.
try this
self.navigationController?.navigationBar.isHidden = false

First present view controller and then push child view controllers

Is there a trick to push to child view controllers from a parent vc that previously has been presented modally?
Method to present parent that I'm using:
let parentVC = ParentController()
self.present(parentVC, animated: true, completion: nil)
Method to then push to child controllers which doesn't work:
let childVC = childController()
navigationController?.pushViewController(childVC, animated: true)
Is there a trick to push to child view controllers from a parent vc
that previously has been presented modally?
If you present a vc modally and you want this vc to push a child vc, you have to present the vc embedded in a UINavigationController.
let parentVC = ParentController()
self.present(parentVC, animated: true, completion: nil)
to become
let parentVC = ParentController()
let parentNav = UINavigationController(rootViewController: parentVC)
self.present(parentNav, animated: true, completion: nil)
then you can do, in parentVC:
let childVC = childController()
navigationController?.pushViewController(childVC, animated: true)

How to reset/restart viewcontroller in Swift?

I want to have a button on my navigation bar "Reset" and I would like this to be connected to an IBAction to sort of "restart" the controller.
I have some segues from another controller that changes some aspects of the viewcontroller (that has a collectionview) and I want the user to be able to start over. Does anyone have any suggestions as to how to proceed?
If you embed navigation controller to your view controller then you can use this code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController")
let viewcontrollers = self.navigationController.viewControllers
viewcontrollers.removeLast()
viewcontrollers.append(vc)
self.navigationControllers?.setViewControllers(viewcontrollers, animate: true)
You can change rootViewController of your application:
UIApplication.shared.keyWindow?.rootViewController = UIViewController()
This is how I do it in Swift 2.1 with my Home view inside a UINavigationController:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let homeVC = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
self.navigationController?.presentViewController(homeVC, animated: false, completion: nil)
self.navigationController?.dismissViewControllerAnimated(false, completion: nil)

Swift presentViewController

I programatically have multiple View Controllers in an iOS Swift Project. I do not have the storyboards and would like to avoid them if possible. Is there a way to switch to another viewcontroller.swift file (We will call it view2.swift) and have it be part of a function that a button calls?I have tried the following:
let storyboard: UIStoryboard = UIStoryboard(name: "myTabBarName", bundle: nil)
let vc: UIViewController = storyboard.instantiateViewControllerWithIdentifier("myVCID") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
The above works with storyboards, but I want another view2.swift to be called. Can this be done?
Try this:
let vc = ViewController() //change this to your class name
self.presentViewController(vc, animated: true, completion: nil)
With Swift3:
self.present(vc, animated: true, completion: nil)
For those getting blank/black screens this code worked for me.
let vc = self.storyboard?.instantiateViewController(withIdentifier: myVCID) as! myVCName
self.present(vc, animated: true, completion: nil)
To set the "Identifier" to your VC just go to identity inspector for the VC in the storyboard. Set the 'Storyboard ID' to what ever you want to identifier to be. Look at the image below for reference.
For reference, because this question is one of the first Google result.
Breaking change in Swift 3:
The method presentViewController is replaced by the method present.
You can use it like the old one:
self.present(viewControllerToPresent, animated: true, completion: nil)
Example to open the camera:
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
Swift 3 and Swift 4
let vc = self.storyboard?.instantiateViewController(withIdentifier: "idMyViewControllerName") as! MyViewControllerName
self.present(vc, animated: true, completion: nil)
For me, I had two views in two separate nav controllers. I had to use a combination of the above.
var vc = self.storyboard?.instantiateViewControllerWithIdentifier("WelcomeViewController") as! WelcomeViewController
var navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
Swift 3.x
let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "VC-ID" as! yourViewController
let navigationVC = UINavigationController(rootViewController: secondVC)
self.present(navigationVC, animated: true, completion: nil)
Using Swift 2.1+
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("settingsVC") as! SettingsViewController
self.presentViewController(vc, animated: true, completion: nil)
Solved the black screen by adding a navigation controller and setting the second view controller as rootVC.
let vc = ViewController()
var navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil
Just use this : Make sure using nibName otherwise preloaded views of xib will not show :
var vc : ViewController = ViewController(nibName: "ViewController", bundle: nil) //change this to your class name
self.presentViewController(vc, animated: true, completion: nil)
You don't need to instantiate the ViewController in Storyboard just to get present() ViewController to work. That's a hackish solution.
If you see a black/blank screen when presenting a VC, it might be because you're calling present() from viewDidLoad() in the First/RootViewController, but the first View isn't ready yet.
Call present() from viewDidAppear to fix this, i.e.:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let yourVC = YourViewController()
self.present(yourVC, animated: true, completion: nil)
}
Once any "View" has appeared in your App, you can start calling present() from viewDidLoad().
Using UINavigationController (as suggested in an answer) is another option, but it might be an overkill to solve this issue. You might end up complicating the user flow. Use the UINavigationController based solution only if you want to have a NavigatonBar or want to return to the previous view controller.
You can use below code :
var vc = self.storyboard?.instantiateViewControllerWithIdentifier("YourViewController") as! YourViewController;
vc.mode_Player = 1
self.presentViewController(vc, animated: true, completion: nil)
Another possibility is that you do not have the XIB included in your Build target (which is what happened to me).
This could happen if you have a different target for Dev, Test & Release Builds (which you should have anyway).
I had a similar issue but in my case, the solution was to dispatch the action as an async task in the main queue
DispatchQueue.main.async {
let vc = self.storyboard?.instantiateViewController(withIdentifier: myVCID) as! myVCName
self.present(vc, animated: true, completion: nil)
}
It's already answered. But adding one more thing while presenting a UIViewController, If anyone is trying to add UIModalPresentationStyle :
if directly presenting the UIViewController as fullScreen:
let viewController = UIViewController()
viewController.modalPresentationStyle = .fullScreen
self.present(viewController, animated: true)
If there is UINavigationController with root view controller as UIViewController:
let viewController = UIViewController()
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = .fullScreen
self.present(navigationController, animated: true)
More helpful answers:
Presenting modal in iOS 13 fullscreen
You can use code:
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as? secondViewController {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = vc
}