Alex Bailey Alex Bailey - 5 months ago 22
Swift Question

Swift Alamofire SwiftyJSON Asynchronous/Synchronous Class Methods

So I currently have the following:

class ViewController: UIViewController {

class Identity{
let baseUrl = "superSecretURL"
var _username: String = ""
var _password: String = ""
var _apiKey: String = ""

init(){

}

init(username: String, apiKey: String){
_username = username
_apiKey = apiKey
}

init(username: String, password: String){
_username = username
_password = password
}

func loginPassword() -> String{
var loginJSON = ["auth": ["passwordCredentials": ["username": _username, "password": _password]]];
var returnJSON: String

request(.POST, baseUrl, parameters: loginJSON, encoding: .JSON)
.responseJSON { (request, response, data, error) in
if let anError = error
{
// got an error in getting the data, need to handle it
println("error calling POST on /posts")
println(error)
}
else if let data: AnyObject = data
{
// handle the results as JSON, without a bunch of nested if loops
let post = JSON(data)
// to make sure it posted, print the results
println("JSON Returned")
}
}
}
}

var i = Identity(username: "secretName", password: "complicatedPassword")

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

println("Before Call")



println("After Call")

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


}


Basically I would like to be able to call the println("Before Call") then receive a response from the loginPassword() method and then println("After Call"). This is I believe synchronous but I can't figure out a way to get it to work and the whole threads thing has baffled my head.

I basically want to be able to say:

if i.loginPassword(){ // do some login stuff }else{ // do some error stuff }


Any help or pointers appreciated.

Answer

You need to set a callback function to be called whenever you want inside your loginPassword() function.

This could be a way of achieving it:

func loginPassword(callback: ((isOk: Bool)->Void)?) -> String{
 var loginJSON = ["auth": ["passwordCredentials": ["username": _username, "password": _password]]];
 var returnJSON: String

 request(.POST, baseUrl, parameters: loginJSON, encoding: .JSON)
   .responseJSON { (request, response, data, error) in
      if let anError = error{
       // got an error in getting the data, need to handle it
        println("error calling POST on /posts")
        println(error)

        callback?(isOk: false)
      }
      else if let data: AnyObject = data{
      // handle the results as JSON, without a bunch of nested if loops
        let post = JSON(data)
       // to make sure it posted, print the results
        println("JSON Returned")

        callback?(isOk: true)
      }
    }
}

and then...

override func viewDidLoad() {
    super.viewDidLoad()

    var identity = Identity(username: "John Apleseed", apiKey: "213123123")

    identity.loginPassword { (isOK) -> Void in
        if (isOK) {
            //do good stuff here
        }else{
           // do error handling here
        }

    }
}

UPDATE

Also, your calling function can look like this:

override func viewDidLoad() {
    super.viewDidLoad()

    var identity = Identity(username: "John Apleseed", apiKey: "213123123")
    identity.loginPassword(handlePasswordRequest)
}

and you can add as many callback handlers as you may need without messing around with a bunch of nested closures...

private func handlePasswordRequest(isOK: Bool){
    if (isOK) {
        //do good stuff here
    }else{
        // do error handling here
    }
}

UPDATE 2

If you are in need to call a callback deep into the hierarchy of calls, then you will need to pass the callback as a parameter of every previous closures.

UPDATE 3

I would give a try to RxAlamofire and all about RxSwift

Comments