Ваша операция асинхронная, способ ожидания завершения — просто использование замыканий, вы пытаетесь вернуть значение вне замыкания, поэтому значение еще не получено!! и это причина вашего пустого значения, вы можете «бросить» completionHandler
внутри вашего закрытия, как в следующем примере:
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)
}
}
}
Тем не менее, описанным выше способом вы не знаете, есть ли какая-то ошибка в запросе, потому что ваш completionHandler
вызывается только внутри случая .Success
, если вы хотите, вы можете вызывать его всегда, после последнего case
из 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)
}
}
И если jsonString
это nil
произошла какая-то ошибка, но вы опять ничего не знаете об ошибке, то у вас есть два варианта:
- Измените закрытие, чтобы всегда возвращать
jsonString
и error
тоже
- Инкапсуляция ошибки в бросаемое замыкание.
Первый случай очень прост, просто измените закрытие и всегда возвращайте ошибку, если это nil
, тогда ошибки не возникло.
Другой вариант, на мой взгляд, лучше, как в следующем примере:
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 })
}
}
}
И тогда вы можете вызвать его следующим образом:
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)
}
}
Хитрость в том, что функция alamoRequest
принимает дополнительное замыкание с именем 'inner'
типа () throws -> String
. Это замыкание либо предоставит результат вычисления, либо выдаст исключение. Само замыкание строится во время вычисления одним из двух способов:
- В случае ошибки:
inner: {throw error}
- В случае успеха:
inner: {return result}
Я настоятельно рекомендую вам отличную статью об использовании try/catch
в асинхронных вызовах Использование try/catch в Swift с асинхронным закрытием
Я надеюсь, что это поможет вам.
person
Victor Sigler
schedule
25.11.2015