Your operation is async, the way of waiting for the completion is just using closures, you're trying to return the value outside the closure so the value is not retrieved yet!! and it's the cause of your empty value, you can "throw" the completionHandler
inside your closure like in the following example :
func alamoRequest(username : String, email: String, password: String, facebook: String, completionHandler : (String?) -> Void) {
var jsonValue : JSON?
let URL = "http://someurl.com/login.php"
let requestParameters = ["username" : username, "email" : email, "password" : password, "facebook" : facebook, "date": NSNull()];
var jsonString : String = String()
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
completionHandler(jsonString)
}
case .Failure(let error):
print(error)
}
}
}
Nevertheless, in the above way the only way of you don't know if exist some error in the request because your completionHandler
is called only inside the .Success
case, if you want you can call it always, after the last case
of the enum
.
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
}
case .Failure(let error):
jsonString = nil
}
completionHandler(jsonString)
}
}
And if the jsonString
is nil
some error has ocurred, but again you don't know anything about the error, then you have two options :
- Change your closure to always return the
jsonString
and the error
too
- Encapsulating the error into a throwable closure.
The first case is very simple, just change your closure and always have the error returned, if it's nil
then no error ocurred.
The other option I think is the better, like in the following example:
func alamoRequest(username : String, email: String, password: String, facebook: String,
completion: (inner: () throws -> String) -> ()) {
var jsonValue : JSON?
let URL = "http://someurl.com/login.php"
let requestParameters = ["username" : username, "email" : email, "password" : password, "facebook" : facebook, "date": NSNull()];
var jsonString : String = String()
Alamofire.request(.GET, URL, parameters: requestParameters).validate().responseJSON {
response in
switch response.result {
case .Success:
if let value = response.result.value {
jsonValue = JSON(value)
jsonString = jsonValue!["error"].stringValue
print("Value in implementation is: \(jsonString)")
completionHandler(inner: { return jsonString })
}
case .Failure(let error):
completionHandler(inner: { return error })
}
}
}
And then you can call it like in the following way:
self.alamoRequest(usernameField.text!, email: emailField.text!, password: passwordField.text!, facebook: "false") { (inner: () throws -> String) -> Void in
do {
let result = try inner()
} catch let error {
print(error)
}
}
The trick is that the alamoRequest
function takes an additional closure called 'inner'
of the type () throws -> String
. This closure will either provide the result of the computation, or it will throw. The closure itself is being constructed during the computation by one of two means:
- In case of an error:
inner: {throw error}
- In case of success:
inner: {return result}
I strongly recommend you an excellent article about using try/catch
in async calls Using try / catch in Swift with asynchronous closures
I hope this help you.