Robert Robert - 2 months ago 9
iOS Question

How to move code execution to the main qeue

I'd like to mention that I've seen a lot of similar questions and tried code from there, but still my code runs asynchronously (I move to another ViewController only after second click on LogIn Button. That's why I would really appreciate you pointing out the problem in my code rather then referencing me to someone's else.

I have a method which sends logIn data to server

import UIKit
var IS_LOGGED_IN = Bool()

class LoginDataSender: UIView {
func sendLogInData() {
let myUrl = NSURL(string: "https://somewebsite")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "username=NAME&password=PASS"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, respoonse, error) in

if error != nil
{
print("error=\(error)")
return
}

dispatch_async(dispatch_get_main_queue(), {
do {
let myJson = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSDictionary

IS_LOGGED_IN = myJson.valueForKey("status") as! Bool
print(IS_LOGGED_IN)

} catch {
print(error)
}
})

}.resume()
}
}


and I call this method from a ViewController

import UIKit

class LoginViewController: UIViewController {

let logInDataSender = LoginDataSender()

@IBAction func pressLoginButton(sender: AnyObject) {

logInDataSender.sendLogInData()

if IS_LOGGED_IN {
performSegueWithIdentifier("LogInSegue", sender: self)

}
}


As you see I store result result in a global variable IS_LOGGED_IN and based on that I whether perform segue or not.
For now I just hardcode login/password for testing purposes.

Where should I place dispatch_async to be able to use IS_LOGGED_IN value when clicking LogIn button for the first time? Thanks a lot!

Answer

Instead of your global variable, make a practice to use completion handlers. In this your case, you may use like:

func sendLogInData(completionhandler: (Bool)->()) {
    //.......
    dispatch_async(dispatch_get_main_queue(), {
            do {
                let myJson = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSDictionary
                completionhandler(myJson.valueForKey("status") as! Bool)
            } catch {
                completionhandler(false)
                print(error)
            }
        })
    //.....
}

And then in your action method of LoginViewController:

 @IBAction func pressLoginButton(sender: AnyObject) {
    logInDataSender.sendLogInData { (loggedIn) in
    if loggedIn == true {
       //Logged In
       performSegueWithIdentifier("LogInSegue", sender: self)
    }else{
       //Not logged in
    }
  }
}