-1

I have simple login method which returns bool, depends on success of user login. I have problem with order of the responses and execution of the code. I've read about completion handlers, which I think are a solution to my problem but I'm not sure. Here is my method:

    //perform user login in, setting nsuserdefaults and returning the bool result
        func login(username: String, password:String) -> (Bool) {

            var success:Bool = false

            //sending inputs to server and receiving info from server
            let postRequest = postDataToURL()
            postRequest.link = "http://pnc.hr/rfid/login.php"
            postRequest.postVariables = "username=" + username + "&password=" + pass

word

        postRequest.forData("POST") { jsonString in
            // getting the result from the asinhronys task
            let result = convertStringToDictionary(jsonString as String)
            if let loggedIn = result?["loggedIn"] as? Bool where loggedIn == true {

                let userType = result?["userType"] as? String
                let token = result?["token"] as? String

                //if user is logged - setting parameters in Key Chains and redirecting them to the menu view
                let defaults = NSUserDefaults.standardUserDefaults()
                defaults.setObject(loggedIn, forKey: "loggedIn")
                defaults.setObject(username, forKey: "username")
                defaults.setObject(userType, forKey: "userType")
                defaults.setObject(token, forKey: "token")

                success = true
            }
            else {
                success = false
            }
            print ("class - " + String(jsonString))
            print ("classIN - " + String(success))
        }

        print ("classOUT - " + String(success))
        return success
    }

I would like to make return of success variable inside if statement which checks variable loggedIn is equal to true. But in that case I get error.

Then I have made this method. The problem is that method returns the variable success quicker than the POST request has been done. So it will be false in every case. I have printed variables to see the order of the code execution and method first prints the "classOUT", returns the variable, and then sets up variable value and print "classIN".

How can I wait until the code which logs user gets executed so I can get the right value of the variable success?

Dravidian
  • 9,945
  • 3
  • 34
  • 74
  • 1
    This is the single most often answered and asked question about iOS on Stack Overflow. Please search before asking. Search on terms like "asynchronous". You cannot "return" anything that depends on an asynchronous function because the function happens after you've returned. – matt Aug 20 '16 at 21:34

2 Answers2

0

Perform user login in, setting nsuserdefaults and returning the bool result

completionBlock: is that block which will get executed when you call it like any block but you get to choose when and what all to pass through that block.

    func login(username: String, password:String,completionBlock : ((success : Bool)->Void)){

        //sending inputs to server and receiving info from server
        let postRequest = postDataToURL()
        postRequest.link = "http://pnc.hr/rfid/login.php"
        postRequest.postVariables = "username=" + username + "&password=" + password

    postRequest.forData("POST") { jsonString in
        // getting the result from the asinhronys task
        let result = convertStringToDictionary(jsonString as String)
        if let loggedIn = result?["loggedIn"] as? Bool where loggedIn == true {

            let userType = result?["userType"] as? String
            let token = result?["token"] as? String

            //if user is logged - setting parameters in Key Chains and redirecting them to the menu view
            let defaults = NSUserDefaults.standardUserDefaults()
            defaults.setObject(loggedIn, forKey: "loggedIn")
            defaults.setObject(username, forKey: "username")
            defaults.setObject(userType, forKey: "userType")
            defaults.setObject(token, forKey: "token")

            completionBlock(success:true)
        }
        else {
            completionBlock(success:false)
        }
    }
}

when you call it would look something like this:-

    login(username: String, password:String,completionBlock : { (success) in
     print(success)
  })
Dravidian
  • 9,945
  • 3
  • 34
  • 74
  • what is completionBlock? how to make call of func which is defined like this? – Pix And Codes Aug 20 '16 at 21:36
  • 1
    its basically another parameter in your function. the nice thing is it's a function too – ha100 Aug 20 '16 at 21:51
  • I advise against saving your token in NSUserDefaults because it's pretty easily accessible as it's just stored in your /library. If someone wants to make REST API calls outside of the app it's way easier than if you store the app in the Keychain. I would treat it like you would a password –  Aug 20 '16 at 22:22
0

you could do something like this

func login(username: String, password: String, completion: (Bool) -> ()) {


    ... YOUR USUAL NETWORKING CODE ...


    completion(success)

}

and then call it

login(username: anonymous, password: ******) { authStatus in

    if authStatus == true {
        print("user in")
    } else {
        print("try one more time")
    }

}
ha100
  • 1,563
  • 1
  • 21
  • 28