2016-12-27 8 views
2

Есть ли способ вызвать запрос alamofire извне ViewController (UITableViewController), а затем заполнить tablewView данными из ответа? прямо сейчас я создал func внутри контроллера, и после извлечения данных просто вызовите reloadData() таблицы tablewView. Но есть ли способ создать такой метод:Запрос Alamofire извне ViewController

class InsuranceServices { 

    class func getContracts(table : UITableView) -> [Contract] { 
     var contracts = [Contract]() 
     let headers : HTTPHeaders = [ 
      "Content-Type":"application/json" 
     ] 
     let params : Parameters = [String:Any]() 

     Alamofire.request("http://test:9090/testService/getContracts", method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).validate().responseJSON(completionHandler: {response -> Void in 

      switch response.result { 
      case .success(let value): 
       let json = JSON(value) 
       for data in json["data"].arrayValue { 
        let contract = Contract(json: data) 
        print(contract.fullName!) 
        contracts.append(contract) 
       } 
      case .failure(let error): 
       print(error) 
      } 
      table.reloadData() 
     }) 
     return contracts 
    } 

} 

Этот метод не работает для меня. может быть, есть другой способ? Я думаю, что создать методы обслуживания внутри контроллера неверно.

ответ

5

У вас должно быть четкое разделение между вашими ViewController и Alamofire. Способ достижения этого похож на то, что вы написали, но вместо того, чтобы принимать сам UITableView, ваша функция должна взять блок завершения, который получает [Contract].

Это может выглядеть примерно так:

class func getContracts(completion: @escaping ([Contract])→Void) { 
    //... 
    Alamofire.request(...).responseJSON(completionHandler: {response -> Void in 

     switch response.result { 

     case .success(let value): 
      let json = JSON(value) 
      var contracts = [Contract]() 
      for data in json["data"].arrayValue { 
       let contract = Contract(json: data) 
       contracts.append(contract)      
      } 
      completion(contracts) 

     case .failure(let error): 
      print(error) 
      completion([]) 
     } 
    }) 
} 

Другое дело, что вы не можете вернуть результат запроса (в вашем случае массив Contract) в возвращаемом значении функции. Поскольку Alamofire запросит асинхронный запрос, он завершится намного позже, чем возврат вашей функции. Вот почему, поскольку вы видите, что подпись функции, которую я написал, ничего не возвращает. Вместо этого он вызывает закрытие completion, когда запрос готов и данные доступны.

Обратите внимание, что вы должны называть completion закрытием даже при отказе! В противном случае вызывающий абонент (в вашем случае контроллер вашего вида) будет ждать запроса навсегда, не зная, что это не сработало.

После этого вы можете вызвать функцию таким образом, чтобы убедиться, что вы не вызываете утечку памяти с помощью self :

InsuranceServices.getContracts(completionHandler: { [weak self] data in 
    self?.contracts = data 
    self?.tableView.reloadData() 
}) 
+0

Og my God, я полностью забываю о @ escaping. на стороне контроллера я назвал эту функцию таким образом: InsuranceServices.getContracts (completeHandler: {данные в self.contracts = данные self.tableView.reloadData() }), и это сработало. большое спасибо! –

+3

Поскольку это '@ escaping', как вы упомянули, вам следует избегать« самоутверждения ». Представьте себе ситуацию, когда вы отклонили контроллер вида, и только позже запрос вернется - сам, но останется в памяти, даже если вы отклонили экран. Чтобы этого не произошло, вы должны придерживаться «слабой» ссылки на себя. Я отредактировал свой ответ с вызовом ... –

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