Raju Gupta
Raju Gupta

Reputation: 33

Tried to pop to a view controller that doesn't exist swift 5.1 Xcode iOS

i'm Working on App. when i'm clicking on logout button its shows me this error Tried to pop to a view controller that doesn't exist.

here is my StoryBoard Screens **All Screen**

**login SignUp Screen**

**profile screen with tabbar & navigationController**

here is my AppDelegate code

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    if #available(iOS 13.0, *)
    {
    //do nothing we will have a code in SceneceDelegate for this
    }
    else {

            makeRoot()
    }
    FirebaseApp.configure()
    return true
}

func makeRoot()
{
    let defaults = UserDefaults.standard

    if defaults.bool(forKey: "isLogin") == true
    {
        let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let VC = mainStoryboard.instantiateViewController(withIdentifier: "RootTabBarC") as! RootTabBarC
        let centerNavVC = UINavigationController(rootViewController: VC)
        //centerNavVC.isNavigationBarHidden = true
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.rootViewController = centerNavVC
        self.window?.makeKeyAndVisible()

    }
    else
    {
        let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let VC = mainStoryboard.instantiateViewController(withIdentifier: "LoginSignUpVC") as! LoginSignUpVC
        let centerNavVC = UINavigationController(rootViewController: VC)
        //centerNavVC.isNavigationBarHidden = true
        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.rootViewController = centerNavVC
        self.window?.makeKeyAndVisible()
    }



}

here is my SceneDelagate code

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    guard let windowScene = (scene as? UIWindowScene) else { return }

    let defaults = UserDefaults.standard

    if defaults.bool(forKey: "isLogin") == true
    {
        //guard let windowScene = (scene as? UIWindowScene) else { return }


        self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let rootVC = storyboard.instantiateViewController(identifier: "RootTabBarC") as? RootTabBarC else {
            print("ViewController not found")
            return
        }
        let navVc = UINavigationController(rootViewController: rootVC)
        //navVc.isNavigationBarHidden = true
        self.window?.rootViewController = navVc
        self.window?.makeKeyAndVisible()
    }
    else
    {
        self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let rootVC = storyboard.instantiateViewController(identifier: "LoginSignUpVC") as? LoginSignUpVC else {
            print("ViewController not found")
            return
        }
        let navVc = UINavigationController(rootViewController: rootVC)
        //navVc.isNavigationBarHidden = true
        self.window?.rootViewController = navVc
        self.window?.makeKeyAndVisible()
    }



}

here is my LoginSignUpVc code

import UIKit

class LoginSignUpVC: UIViewController {

@IBOutlet weak var lblTitle: UILabel!
@IBOutlet weak var btnLogin: UIButton!
@IBOutlet weak var lblDontHaveAccount: UILabel!
@IBOutlet weak var btnSignUp: UIButton!


override func viewDidLoad() {
    super.viewDidLoad()


    setupUI()
}

override func viewWillAppear(_ animated: Bool) {
    navigationController?.setNavigationBarHidden(false, animated: true)
}
override var prefersStatusBarHidden: Bool
{
    return true
}

func setupUI()
{
    letterSpacing()
    buttonSetUp()
}

@IBAction func onClickLogin(_ sender: Any)
{

}

@IBAction func onClickSignUp(_ sender: Any)
{

}

}

here is my LoginVc code

import UIKit
import FirebaseAuth

class LoginVC: UIViewController {

@IBOutlet weak var lblTitle: UILabel!
@IBOutlet weak var lblSubTitle: UILabel!
@IBOutlet weak var viewContainerEmail: UIView!
@IBOutlet weak var txtEmail: UITextField!
@IBOutlet weak var viewContainerPassword: UIView!
@IBOutlet weak var txtPassword: UITextField!
@IBOutlet weak var btnLogin: SSSpinnerButton!
@IBOutlet weak var btnForgotPassword: UIButton!


override func viewDidLoad() {
    super.viewDidLoad()

    navigationController?.navigationBar.layer.frame.origin.y = 22
    setupUI()

}

override func viewWillDisappear(_ animated: Bool) {
    btnLogin.stopAnimate(complete: nil)
}

override var prefersStatusBarHidden: Bool
{
    return true
}

func setupUI()
{
    letterSpacing()
    textFieldSetUp()
    buttonSetUp()
}

@IBAction func onClickLogin(_ sender: Any)
{
    let email = Validation.shareValidator.isValidEmail(email: txtEmail.text, view: viewContainerEmail)
    let password = Validation.shareValidator.isValidPassword(password: txtPassword.text, view: viewContainerPassword)
    if email != "success"
    {
        CustomAlert.shareAlert.alertSetUp(title: "Email Field", subTitle: email, boldTitle: "Invalid Email")
    }
    else if password != "success"
    {
        CustomAlert.shareAlert.alertSetUp(title: "Password Field", subTitle: password, boldTitle: "Invalid Password")
    }
    else
    {
        Auth.auth().signIn(withEmail: txtEmail.text!, password: txtPassword.text!) { (result, error) in
            if error != nil
            {
                CustomAlert.shareAlert.alertSetUp(title: "Login Error", subTitle: error!.localizedDescription, boldTitle: "Login Error")
            }
            else
            {
                self.btnLogin.startAnimate(spinnerType: SpinnerType.circleStrokeSpin, spinnercolor: UIColor.white, spinnerSize: 20, complete: {
                    self.btnLogin.backgroundColor = UIColor.green

                    let defaults = UserDefaults.standard

                    defaults.set(true, forKey: "isLogin")
                    defaults.set(result?.user.uid, forKey: "uid")
                    defaults.set(self.txtEmail.text!, forKey: "email")
                    //let st = UIStoryboard(name: "Main", bundle: nil)
                    let vc = self.storyboard?.instantiateViewController(withIdentifier: "RootTabBarC") as! RootTabBarC
                    self.navigationController?.pushViewController(vc, animated: true)
                })
            }
        }

    }
}

@IBAction func onClickBack(_ sender: Any)
{
    navigationController?.popViewController(animated: true)
}

}

here is my ProfileVC code

import UIKit
import FirebaseAuth
import FirebaseDatabase
import Kingfisher

class ProfileVC: UIViewController {

@IBOutlet weak var viewImageContainer: UIView!
@IBOutlet weak var imgProfile: UIImageView!
@IBOutlet weak var lblName: UILabel!
@IBOutlet weak var lblDishExpert: UILabel!
@IBOutlet weak var lblBio: UILabel!
@IBOutlet weak var imgEmailIcon: UIImageView!
@IBOutlet weak var imgPhoneIcon: UIImageView!
@IBOutlet weak var lblEmail: UILabel!
@IBOutlet weak var lblPhone: UILabel!
var userDataDict = [String]()

override func viewDidLoad() {
    super.viewDidLoad()

    setUpUI()
    showUserData()
}

@IBAction func onClickLogOut(_ sender: Any)
{
    do
    {
        try Auth.auth().signOut()

        UserDefaults.standard.set(false, forKey: "isLogin")
        UserDefaults.standard.removeObject(forKey: "uid")
        UserDefaults.standard.removeObject(forKey: "email")
        UserDefaults.standard.synchronize()

    }
    catch let err
    {
        print(err.localizedDescription)
    }


    let vc = storyboard?.instantiateViewController(identifier: "LoginSignUpVC") as? LoginSignUpVC

    navigationController?.popToViewController(vc!, animated: true)

}



}

i'm also try self.parent?.navigationController?.PopToRootViewController(animate:true) but is not working propely. thank for your help.

Upvotes: 2

Views: 1508

Answers (2)

Dikey
Dikey

Reputation: 121

Vasucd is right, put LoginSinUpVC in NavigationController’s viewControllers first

——————Edited—————-

As error indicates, this is because you init a new viewController that dose not exist in NavigationController's viewControllers

let vc = storyboard?.instantiateViewController(identifier: "LoginSignUpVC") as? LoginSignUpVC

to solve the problem, try to find LoginSignUpVC in navigationController's viewControllers

for vc in navigationController.viewControllers {
    if let loginSignUpVC  = vc as? LoginSignUpVC {
        navigationController?.popToViewController(loginSignUpVC, animated: true)
    }
}

Upvotes: 1

Vasucd
Vasucd

Reputation: 357

When you first time open your screen you are setting up NavigationController and adding login or tab Controller according your loggedIn functionality . So if let say I start the app , it's take me to the TabBar Controller and now I'm pressing logout button to go login Controller .

But there is no such controller in navigation stack . So I suggest you to call you scene method again for setting up login controller as rootController.

What best you can do is make separate functionality in scene class for logged in and logged out state.

func navigateToHomeVC(){
     self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let rootVC = storyboard.instantiateViewController(identifier: "RootTabBarC") as? RootTabBarC else {
            print("ViewController not found")
            return
        }
        let navVc = UINavigationController(rootViewController: rootVC)
        //navVc.isNavigationBarHidden = true
        self.window?.rootViewController = navVc
        self.window?.makeKeyAndVisible()
}


func navigateToLoginVC(){
      self.window = UIWindow(windowScene: windowScene)
        //self.window =  UIWindow(frame: UIScreen.main.bounds)

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let rootVC = storyboard.instantiateViewController(identifier: "LoginSignUpVC") as? LoginSignUpVC else {
            print("ViewController not found")
            return
        }
        let navVc = UINavigationController(rootViewController: rootVC)
        //navVc.isNavigationBarHidden = true
        self.window?.rootViewController = navVc
        self.window?.makeKeyAndVisible()
}


func makeRoot()
{

    let defaults = UserDefaults.standard

    if defaults.bool(forKey: "isLogin") == true
    {
       navigateToHomeVC()

    }
    else{
        navigateToLoginVC()
    }
}

Now call this navigateToLoginVC() function of scene class when logout button pressed.

Hope this helps.

Upvotes: 1

Related Questions