0

I am developing an application for a username-password based system. My initial view controller is named LoginPageViewController. If the user logs in successfully, a navigation controller named MyNavigationController is loaded. All view controllers except LoginPageViewController are accessed via a side-menu I found here: Side Menu Library by the help of MyNavigationController.

View settings of my side menu are described in MyMenuTableViewController and if any of table items is selected, relevant view controller is loaded from MyMenuTableViewController. The problem is, I have also added "Logout" item to my side menu (or menu table, whatever you call) and if this item is selected, it makes an HTTP POST request to server to log out and should load the LoginPageViewController which is my initial view controller (which is not embedded in MyNavigationControlelr).

The problem is, although the logout request is handled successfully, I have been encountering problems while loading my initial view controller (LoginPageViewController).

When I try this when Logout is selected:

self.presentViewController(destViewController, animated: true, completion: nil)

LoginPageViewController is being loaded but I get an message like:2014-10-30 16:59:26.038 iOpsGenie[2973:66509] Presenting view controllers on detached view controllers is discouraged <iOpsGenie.MyMenuTableViewController: 0x7f85e8fc3f10>. and if I click any where on Login Page, my view disappears and only a white screen is left.

Then I tried implementing a method

 func resetAppToFirstController() {
     self.window?.rootViewController = LoginPageViewController(nibName: nil, bundle: nil)
     }

in AppDelegate.swift and call it when Logout item is being selected:

let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.resetAppToFirstController()

Then I got an error in second line of viewDidLoad function of LoginPageViewController like:

fatal error: unexpectedly found nil while unwrapping an Optional value

I know it became a very long question. I may be counted as a newbie on Swift and iOS programming and I tried to state the problem to prevent irrelevant responses. I really wonder what I am missing.

Best regards

Dharmesh Kheni
  • 67,254
  • 32
  • 154
  • 160
natuslaedo
  • 429
  • 7
  • 16
  • When instantiating the LoginPageVC in your resetApp() you should be passing a xib name instead of nil for the first parameter. Swift does not find the nib with the same name as the VC like objective-C does. – JMFR Oct 30 '14 at 16:00

4 Answers4

3

I solved the problem by changing resetAppToFirstController method to:

self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(PageNames.LOGIN_PAGE) as LoginPageViewController

and firing the following code when Logout is clicked:

let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.resetAppToFirstController()

However, I have no idea why this is worked. Any little explanation would be great.

natuslaedo
  • 429
  • 7
  • 16
2

In swift we can change the root view controller and in that case all other view controllers will be deallocated and they will no longer be in the hierarchy.

To load initial view controller or to change root view controller or to make logout action in swift

let storyboard = UIStoryboard(name: "StartingPage", bundle: NSBundle.mainBundle())      
let loginView: SignInVC = storyboard.instantiateViewControllerWithIdentifier("SignInVC") as! SignInVC
UIApplication.sharedApplication().keyWindow?.rootViewController = loginView
Nischal Hada
  • 3,050
  • 2
  • 24
  • 52
0

Please allow me to suggest a better way to do what you want, ok? I had a similar problem in another question I posted; please look at the accepted answer at this question.

Pay attention to the storyboard on the answer. It has a hierarchy of view controllers which allow start from a Login Controller, navigate through several controllers and perform a Logout from a menu.

In order to implement this, follow these steps.

  1. Make your initial view controller a navigation controller, with root view being your Login controller.

  2. Make your login controller Push Segue the Menu controller.

  3. Perform an "unwind segue" from the Logout button of the menu view to the login view.

An unwind segue will remove all the views from a navigation stack until it reaches a view you specify.

Unwind segues are really easy to use and can solve a lot of problems!

Add the following method definition on your login view controller:

@IBAction func unwindToLoginScreen(segue:UIStoryboardSegue) {
}

Then, on storyboard editor, select any view controller from which you want to be able to unwind. On the top of the view controller you have three icons.

enter image description here

The first represents the view controller; the second is the First Responder; the third is an Exit door.

Perform a "Control+Drag" from the first to the third icon; a drop down menu will appear referencing all the "unwind segue" declarations you made on your code. Our unwindToLoginScreen segue should appear here. Select it.

enter image description here

On the Document Outline at the left bar of the storyboard editor will appear an Unwind Segue on the hierarchy of the view controller. Select it and change its identifier to something like "Login".

Now, you can call performSegueWithIdentifier("Login") if you want to go back to the login screen.

The advantages of using unwind segues is that you know for sure that all the views in the stack are being deallocated, that you can call preparation code in the prepareForSegue method in the origin view controller, some code in your destination view controller just before finishing the segue; and that connections between different view controllers are visible on the storyboard editor (not so evident as in regular segues, though).

Community
  • 1
  • 1
Felipe Ferri
  • 3,179
  • 1
  • 26
  • 37
0

Swift 4

Syntax is changed in swift4 : If you want to go to "FirstViewController" in StoryBoard "Main" try below code

let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

let firstviewcontroller = storyboard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController

UIApplication.shared.keyWindow?.rootViewController = firstviewcontroller