2015-11-25 8 views
2

Я не могу понять, как это понять: я пытаюсь получить сообщение об ошибке с моего сервера (в JSON) с использованием запроса Alamofire, но я не могу получить значение вне функция.Использование значения из запроса Alamofire вне функции

Это реализация моей функции:

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)") 

      } 
     case .Failure(let error): 
      print(error) 
     } 
    } 
    completionHandler(jsonString) 
} 

А вот как я это называю:

logic.alamoRequest(usernameField.text!, email: emailField.text!, password: passwordField.text!, facebook: "false") { 
      json in 
      jsonString = json! 
     } 

     alamoRequest = jsonString 
     print("Value in call is: \(alamoRequest)) 

Но выход всегда так:

Value from call is: Value in implementation is: Email already exists

Как я могу «вернуть» что-то из функции или дождаться ее выполнения без блокировки пользовательского интерфейса?

ответ

5

Ваша операция async, способ ожидания завершения заключается в том, что вы используете закрытие, вы пытаетесь вернуть значение за пределы закрытия, так что значение еще не получено! и это причина вашего пустого значения, вы можете «выбросить» на 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, если вы хотите, вы можете называть его всегда, после последнего caseenum.

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 имеет ocurred некоторых ошибок, но опять же вы ничего об ошибке не знаете, то у вас есть два варианта:

  1. Поменяйте ваше замыкание всегда возвращать jsonString и error
  2. Инкапсулирование ошибки в бросающееся закрытие.

Первый случай очень прост, просто измените свое закрытие и всегда возвращайте ошибку, если это 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 in async calls Using try/catch in Swift with asynchronous closures

Надеюсь, это поможет вам.

+0

Большое спасибо Виктору, очень подробный и проницательный ответ, это действительно помогло мне! :-) –

Смежные вопросы