Sign Out button to Present Login View Controller - Swift 5 - swift

Hi I'm kind of new to Swift and I can't figure this out. I am trying to create a sign out button that would take user to the login page. I used the following two methods but the first one doesn't do anything and the second one is throwing Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value and it refers to the code with the customButton:
//this one doesn't do anything
#objc func SignOut(){
let vc = self.storyboard?.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
let appDelegate = UIApplication.shared.delegate
appDelegate?.window??.rootViewController = vc
}
//this one is throwing an error
let vc = CustomViewController()
self.present(vc, animated: true, completion: nil)
//the Fatal error refers to this code
override func viewDidLoad() {
super.viewDidLoad()
self.customButton.addTarget(self, action: #selector(customButtonPressed), for: .touchUpInside)
}
Also, I was wondering if AppDelegate is the right approach or if I should use SceneDelegate. Any help would be greatly appreciated.

Try to do this
#objc func SignOut(){
let vc = self.storyboard?.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
self.view.window?.rootViewController = vc
}

let vc = self.storyboard?.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true, completion: nil)
Please make sure the identifier is matching the one inside storyboard for this viewController

Related

How do you present a VC from Xib in Swift?

I am trying to present a VC from a Xib file but it's resulting in
Fatal error: Unexpectedly found nil while unwrapping an Optional value
#IBAction func viewCartBtnTapped(_ sender: Any) {
let cart = storyboard?.instantiateViewController(withIdentifier: "CartVC") as? CartVC
present(cart!, animated: true, completion: nil)
}
try below code, YourStoryBoradName should be the name of storyboard without ".storyboard" extension :
let storyBoard : UIStoryboard = UIStoryboard(name: "YourStoryBoradName", bundle:nil)
let viewController = storyBoard.instantiateViewController(withIdentifier: "CartVC")as! CartVC
self.present(viewController, animated: true, completion: nil)

Prevent ViewController from stacking in the background when created with present

I use this code to open a new ViewController:
// Get a random next post
#IBAction func buttonNextPostTapped(_ sender: UIButton) {
let postNumber = Int.random(in: 0 ..< postIds.count)
let postId = postIds[postNumber]
PostApi.shared.getPost(postId: postId) { (post) in
let storyBoard : UIStoryboard = UIStoryboard(name: "MainApplication", bundle: nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "PostsViewController") as! PostsViewController
nextViewController.post = post
nextViewController.isFromRandom = true
self.present(nextViewController, animated: true, completion: {})
}
}
This code will open the same ViewController with different data. It works, however, the "old" ViewControllers will stack in the background. So if I open 10 new ViewControllers, I have 10 VC in the background.
How can I present a new ViewController, and dismiss the "old" one?
Using setViewControllers function from UINavigationController is the best way.
func setViewControllers(_ viewControllers: [UIViewController], animated: Bool)
And you can remove whichever controller you want to from stack like
if var navigationControllersArray:Array = (self.navigationController?.viewControllers) {
navigationControllersArray.remove(at: navigationControllersArray.count-2)
self.navigationController?.viewControllers = navigationControllersArray
}

how to open 'LGSideMenuController' side menu open from all viewcontroller?

I used 'LGSideMenuController' in my project. but it cannot open from my all viewcontroller. I want to open sidemenu in all my viewcontroller in my project. But right now I am able to open it from my 'HomeViewcontroller' and only for one time.
In my AppDelegete.swift file I make function and it called in otpviewcontroller.
func createSideMenu(){
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
let rootviewcontroller = storyBoard.instantiateViewController(withIdentifier: "HomeVC") as! HomeVC
let navigation = UINavigationController.init(rootViewController: rootviewcontroller)
let sideMenuVC = storyBoard.instantiateViewController(withIdentifier: "SideMenuVC") as! SideMenuVC
let sideMenuController = LGSideMenuController(rootViewController: navigation,
leftViewController: sideMenuVC,
rightViewController: nil)
sideMenuController.leftViewWidth = 280.0
sideMenuController.leftViewPresentationStyle = .scaleFromBig
self.window?.rootViewController = sideMenuController
self.window?.makeKeyAndVisible()
}
In my 'Homeviewcontroller' and otherviewcontroller I open sidemenu like this.
#IBAction func sideMenuAction(_ sender: UIBarButtonItem) {
self.sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
It open in only HomeViewcontroller but I want to open it in all Viewcontroller of my project. I am new in swift. Please help me. Thank you.
You can use the same method to open "LGSideMenuController" as you did in "HomeViewcontroller".
Suppose in another viewcontroller, you want to open "LGSideMenuController" on click of button event then code will look like
#IBAction func openSideMenu(_ sender: Any) {
self.sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
Edit Answer
I checked your code and found that you are trying to present another viewcontroller screen over "LGSideMenuController" instead of using push transition.
Please change your code in SideMenuVC controller as below
#IBAction func eventsAction(_ sender: Any) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "EventsVC") as! EventsVC
//let navigationController = UINavigationController(rootViewController: vc)
//self.present(navigationController, animated: true, completion: nil)
self.sideMenuController?.hideLeftViewAnimated()
self.sideMenuController?.rootViewController?.show(vc, sender: self)
}
In the above code, i hide the sidemenu first and then push "EventsVC" view controller in sideMenuController. Please apply the same code on other button actions.
Hope it helps.

Swift: Can't use navigationController.pushViewController inside a function

I am transitioning between views programatically using the code below and it gets repeated quite a lot so I wanted to create a global function but I can't seem to be able to get the hang of it.
The code works when called inside a ViewController class, so I suppose the problem is that my function doesn't know which VC do I want to call navigationController.pushViewController on, but I don't know how to reference the VC either as an argument passed to the function, or better yet with something like .self to take the current VC class the function is called in.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ExamplesControllerVC")
self.navigationController?.pushViewController(vc, animated: true)
The error I get if I try to run that as a function in a separate file is:
Use of unresolved identifier 'navigationController'; did you mean 'UINavigationController'?
So the function I'd like to create and call is something like:
showVC("ExamplesControllerVC")
Any ideas?
Whatever function this code is in needs to be updated to take a parameter of type UIViewController.
func showMain(on vc: UIViewController) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ExamplesControllerVC")
vc.navigationController?.pushViewController(vc, animated: true)
}
Now you can call this as:
showMain(on: someViewController)
Or add this function to an extension on UIViewController then your use of self works just fine.
extension UIViewController {
func showMain() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ExamplesControllerVC")
self.navigationController?.pushViewController(vc, animated: true)
}
}
Do you want to do something like this?:
extension UIViewController {
func presentView(withIdentifier: String) {
if let newVC = self.storyboard?.instantiateViewController(withIdentifier: withIdentifier) {
self.present(newVC, animated: true, completion: nil)
}
}
}
You can call it this way:
self.presentView(withIdentifier: "yourIdentifier")

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
}