Bhavik P.
Bhavik P.

Reputation: 915

Waiting for Callback Function to Finish : Swift

I want to change the view when the user logs in from the LoginController. When access = true, change controller. However, I cant do it within the user.login because it gives me an error saying I have to process this on the main thread. Now I know that there are solutions for this, but I have been searching for a week and ran around in circles. I have gotten close enough to produce what I have below.

I have 3 pieces of information that I would like to share: LoginController:

var access = false
        user.login(
            {(response: Bool) -> () in
                access = response
                print(access)
            },username: emailField.text!, password: passwordField.text!)
        if(access){
            print("YAY")
            let controller = storyboard?.instantiateViewControllerWithIdentifier("NewsFeed") as! NewsFeed
            presentViewController(controller, animated: true, completion: nil)
        }else{
            print("NAY")
        }

LoginClass:

func login(completionHandler : (response: Bool) -> (), username: String, password: String){
    //Set the calback with the calback in the function parameter
    let parameters : [String: AnyObject] = ["tag": "login", "email": username, "password": password]
    manager.postDataToServer(
        {(response: NSDictionary) -> () in
            if(response["success"] as! Int == 1){
                // Log user in
            }else{
                // User not able to login

                }
                completionHandler(response: false)
            }
        }, page: "login", params: parameters)
}

APIManager:

func postDataToServer(completionHandler: (response: NSDictionary) -> (), page: String, params: [String: AnyObject]){
    // Gets the information and returns the User
    // Works completely fine

}

ANSWER : Please go down to look at the Updated Answer

Please look at @Rob's answer. However you may get an error message saying Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'. It is because you cannot change views unless its on the main thread. Simply wrap it in

NSOperationQueue.mainQueue().addOperationWithBlock {
        //Change View
    } 

Updated I realized my mistake was that I didn't endEditing in one of my fields before processing the information. I fixed it by doing the following, passwordField.endEditing and also emailField.endEditing (just to be safe)

Upvotes: 1

Views: 1623

Answers (1)

Rob
Rob

Reputation: 438307

Instead of waiting for the response, just move the code you want to perform inside the closure:

user.login( { response in
    if response {
        print("YAY")
        let controller = self.storyboard?.instantiateViewControllerWithIdentifier("NewsFeed") as! NewsFeed
        self.presentViewController(controller, animated: true, completion: nil)
    } else {
        print("NAY")
    }
}, username: emailField.text!, password: passwordField.text!)

Even better, I'd change the order of those parameters, so that the closure was the last parameter (and you can then use "trailing closure" syntax):

func loginWithUsername(username: String, password: String, completionHandler : (response: Bool) -> ()) {
    // your login code here
}

And then:

user.loginWithUsername(emailField.text!, password: passwordField.text!) { response in
    if response {
        print("YAY")
        let controller = self.storyboard?.instantiateViewControllerWithIdentifier("NewsFeed") as! NewsFeed
        self.presentViewController(controller, animated: true, completion: nil)
    } else {
        print("NAY")
    }
}

Upvotes: 2

Related Questions