简体   繁体   English

如何使用 Alamofire 发出同步请求?

[英]How to make a synchronous request using Alamofire?

I am trying to do a synchronous request using Alamofire .我正在尝试使用Alamofire进行同步请求。 I have looked on Stackoverflow and found this question: making an asynchronous alamofire request synchronous .我查看了 Stackoverflow 并发现了这个问题: 使异步 alamofire 请求同步

I saw that the accepted answer uses completion to make Alamofire request synchronous but I cannot make it to work.我看到接受的答案使用completion来使Alamofire请求同步,但我无法使其工作。 This is my simplified code:这是我的简化代码:

func loadData(completion: (Bool)) -> (Int, [String], [String], [String]){

    Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in

        switch(response.result) {
        case .success(_):
            if let JSON = response.result.value as! [[String : AnyObject]]!{
                 //Here I retrieve the data
            }

            completion(true)
            break

        case .failure(_):
            print("Error")
            completion(false)
            break  
        }
   }

   return (numberRows, nameArray, ageArray, birthdayArray)
}

With this code I am getting an error when trying to make completion(bool value) .使用此代码,我在尝试completion(bool value)时遇到错误。 The error that I am getting is the following:我得到的错误如下:

Cannot call value of non-function type 'Bool'无法调用非函数类型“Bool”的值

I have tried using a lot of examples using completion to get the values synchronously (because I need to retrieve the data before to show it on a table and at the same time get the number of rows of that table) without success.我已经尝试使用很多示例使用完成来同步获取值(因为我需要先检索数据以将其显示在表上并同时获取该表的行数),但没有成功。

How can I use that completion to get a synchronous response?如何使用该完成来获得同步响应?

Thanks in advance!提前致谢!

when you use completion handler do not use return. 当你使用完成处理程序时不要使用return。

func loadData(completion: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ()){

  Alamofire.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { response in

    switch(response.result) {
    case .success(_):
        if let JSON = response.result.value as! [[String : AnyObject]]!{
            //Here I retrieve the data
        }
        completion(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray)
        break

    case .failure(_):
        print("Error")
        completion(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray)
        break
    }
  }
}

loadData (completion: { (number, strArr1, strArr2, strArr3) in
    // do it
    // for exapmple
    self.number = number
    self.strArr1 = strArr1
    // and so on

})

or if you want return any value in closure you must use completion handler for return any value or some thing like, for example if you want return Boolean value: 或者如果你想在闭包中返回任何值,你必须使用完成处理程序来返回任何值或某些东西,例如,如果你想返回布尔值:

func loadData(completion:(number: numberRows, strArr1 : nameArray, strArr2 : ageArray, strArr3: birthdayArray) -> (Bool))

and in the loadData 并在loadData

loadData( completion: { ( number, strArr1, strArr2, strArr3 ) -> (Bool) in
       # code 
       return False
})

or some think else. 或者其他一些想法。

I use swift 3. but if you want another version of swift careful about External Parameter Names and internal parameter names, like: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ()) 我使用swift 3.但是如果你想要另外一个版本的swift小心外部参数名和内部参数名,比如: @escaping (_ number: Int, _ strArr1: [String], _ strArr2: [String], _ strArr3: [String]) -> ())

if you want set external parameter names, just need drop _ and set name for parameters. 如果你想设置外部参数名称,只需要drop _和set name for parameters。

Note that making synchronous requests is highly discouraged by Apple, for reasons noted here . 请注意,由于此处提到的原因,Apple强烈建议不要发出同步请求。

In this example I'm simplifying the call, if you have more information, such as the content of the cells, I suggest you take a look at SwiftyJSON and return the entire JSON Blob, then parse it in the relevant methods (numberOfRows, etc.). 在这个例子中我简化了调用,如果你有更多的信息,比如单元格的内容,我建议你看一下SwiftyJSON并返回整个JSON Blob,然后用相关的方法解析它(numberOfRows等等) )。

class TableViewJSONAsynchCalls: UIViewController, UITableViewDelegate, UITableViewDataSource {
    var tableView = UITableView()
    var numberOfRows = 0;

    override func viewDidLoad() {
        loadData { (didCompleteRequest) in
            if (didCompleteRequest) {
                tableView.delegate = self
                tableView.dataSource = self
                tableView.reloadData()
            } else {
                // Handle error if data was not loaded correctly
            }
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfRows;
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("selected")
    }

    func loadData(completion: (Bool) -> Void) {
        // Make asynchronous call using alamofire
        // This simulates you parsing the JSON and setting the relevant variables, 
        // personally I would recommend you return a JSON blob and then 
        // parse it in the relevant methods.
        sleep(2)
        // If call is successful
        self.numberOfRows = 10
        completion(true)

    }
}

You can convert any method to synchronous using something like this:您可以使用以下方法将任何方法转换为同步方法:

func getName() -> (String?, Error?) { //an async call is in there
    let semaphore = DispatchSemaphore(value: 0)
    var name: String? // result to return
    var error: Error? // error to throw
    service.getUserName().subscribe { result in //call alamofire or anything
        switch(result) {
          case .success(let res): name = res.name
          case .failure(let err): error = err
        }
    } onFailure: { err in
        error = err
    }.disposed(by: bag)
    semaphore.wait()
    return (name, error)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM