MattEm MattEm - 4 months ago 16
Swift Question

Swift: Change ViewController after Authentication from RESTful API

I have a rails api set up and one test user. I can login/logout view the api.

I have a tab app set up, and I have a LoginViewController set up to authenticate into that. My view controller (basically) looks like the below code. This doesnt work. However, the second block of code does work

I am guessing I am calling something wrong.. The first block executes and then crashes with a *** Assertion failure in -[UIKeyboardTaskQueuewaitUntilAllTasksAreFinished].. I've been spinning my wheels for hours.. tried looking into segues.. etc. Anything would help!!!

//DOES NOT WORK //

class LoginViewController: UIViewController {

@IBOutlet weak var email: UITextField!

@IBOutlet weak var password: UITextField!

@IBAction func Login(sender: AnyObject) {
func switchToTabs() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController

}

let authCall = PostData()
var authToken = ""
authCall.email = email.text!
authCall.password = password.text!
authCall.forData { jsonString in
authToken = jsonString
if(authToken != "") {
switchToTabs()
}
}
}



// SAME CLASS THAT DOES WORK//

class LoginViewController: UIViewController {

@IBOutlet weak var email: UITextField!

@IBOutlet weak var password: UITextField!

@IBAction func Login(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController


}


My question is, why can I seemingly navigate to a new view when I don't use my api, but when I do receive my auth token.. I can't log in.

Please excuse the ugly code.. this is my first day with swift

Answer

Everytime you every do anything that changed something about the UI inside of a closure or anything that could even possibly be off the main queue, enclose it in this statement.

dispatch_async(dispatch_get_main_queue()) {
    //the code that handles UI
}

This includes all code that segues inside a closure like the one you have

authCall.forData { jsonString in
    authToken = jsonString
    if(authToken != "") {
        switchToTabs()
    }
}

If you write it like so it would work

 authCall.forData { 
    jsonString in
    authToken = jsonString
    if(authToken != "") {
        dispatch_async(dispatch_get_main_queue()) {
            switchToTabs()
        }
    }
}

then call your segue in switchToTabs()

If you arn't sure what queue you are on, it won't hurt to do it. As you become more familiar with scenarios that take you off the main queue, you will realize when to use it. Anytime you are in a closure and dealing with UI its a safe bet that you could leave. Obviously anything asynchronous would cause it as well. Just place your performSegueWithIdentifier inside of it and it should work.

Comments