【问题标题】:Wait for task return on session.dataTask等待 session.dataTask 上的任务返回
【发布时间】:2018-01-04 17:35:54
【问题描述】:

我有一个项目,我从 API 发送和获取数据。发送和获取它工作正常。

我的目标是等待来自服务器的响应(即:yes|no),并根据它,继续或不继续 segue,如果没有则显示警报。

对于这部分我有:

  1. tableview 视图,其中包含客户端列表和添加新客户端的按钮。
  2. 我在其中添加/编辑客户端的详细视图
  3. 在详细视图中,有一个保存按钮,其中包含与 tableview 视图的 segue

函数saveClient()获取数据并向服务器发出请求

func saveClient() -> Bool {

    let name = txtName.text ?? ""
    let address = txtAddress.text ?? ""
    let city = txtCity.text ?? ""
    let province = txtProvince.text ?? ""
    let postal_code = txtPostalCode.text ?? ""

    meal = Client(name:name, client_id: "", postal_code: postal_code, province: province, city: city, address: address)

    var jsonData = Data()
    let jsonEncoder = JSONEncoder()
    do {
        jsonData = try jsonEncoder.encode(meal)
    }
    catch {
    }
    print("a1")
    var success: Bool
    success = false

    makeRequestPost(endpoint: "http://blog.local:4711/api/clients/add",
                    requestType: "POST",
                    requestBody: jsonData,
                    completionHandler: { (response : ApiContainer<Client>?, error : Error?) in
                        if let error = error {
                            print("error calling POST on /todos")
                            print(error)
                            return
                        }
                        let b = (response?.meta)!
                        print(b.sucess)
                        if(b.sucess == "yes") {
                            success = true
                        }
                        else
                        {
                            DispatchQueue.main.async(execute: {
                                let myAlert = UIAlertController(title: "Error", message: "Error creating Client", preferredStyle: .alert)
                                let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
                                myAlert.addAction(okAction)
                                self.present(myAlert, animated: true, completion: nil)
                            })
                            return
                        }
    } )
    return success
}

在同一个控制器上:

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {

    guard let button = sender as? UIBarButtonItem, button === btnSave else {
        return false
    }

    if !saveClient() {
        print("no sir")
        return false
    }

    print("yes sir")
    return true
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)        
    guard let button = sender as? UIBarButtonItem, button === btnSave else {
        return
    }
}

请求函数:

func makeRequestPost<T>(endpoint: String,
                     requestType: String = "GET",
                     requestBody: Data,  completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) {

    guard let url = URL(string: endpoint) else {
        print("Error: cannot create URL")
        let error = BackendError.urlError(reason: "Could not create URL")
        completionHandler(nil, error)
        return
    }

    var urlRequest = URLRequest(url: url)
    let session = URLSession.shared

    urlRequest.httpMethod = "POST"
    urlRequest.httpBody = requestBody

    urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")



    let task = session.dataTask(with: urlRequest, completionHandler: {
        (data, response, error) in
        guard let responseData = data else {
            print("Error: did not receive data")
            completionHandler(nil, error)
            return
        }
        guard error == nil else {
            completionHandler(nil, error!)
            return
        }

        do {
            let response = try JSONDecoder().decode(ApiContainer<T>.self, from: responseData)
            completionHandler(response, nil)
        }
        catch {
            print("error trying to convert data to JSON")
            print(error)
            completionHandler(nil, error)
        }

    })
    task.resume()
}

在控制台上我得到:

a1

没有先生

是的

正确的是:

a1

是的

是的,先生

最后的笔记:

  1. 我尝试了一些带有信号量的示例...但没有成功。

  2. 我在其他地方使用了一个名为餐的 var,并且没有将其更改为客户端。但是,它不会干扰那部分代码

【问题讨论】:

  • 我会在异步调用中使用shouldPerformSegue(withIdentifier:sender:)。我要做的是在用户想要转到另一个视图控制器时手动调用save(),如果成功,请调用if(b.sucess == "yes"){ DispatchQueue.main.async(execute: {self.performSegue(identifier:"mySegueID", sender:something)}})
  • 我认为 Larme 的意思是“我不会使用 ...”。因此,从按钮(或其他)中删除 segue,并使用 @IBAction 方法来执行如 Larme 所说的 segue。
  • 没有转回列表。有一个放松。添加或更新后,我必须显示一个警告说好的,关闭详细视图并返回列表,更新表格。
  • 我按照建议做了...而且效果很好

标签: ios swift task nsurlsession


【解决方案1】:

你说:

我的目标是等待来自服务器的响应(即:是|否),并根据它,继续或不继续

虽然我理解这种方法的自然吸引力,但现实情况是您永远不应该“等待”(尤其是在 shouldPerformSegue 中)。您的 UI 将冻结(尤其是当用户的 Internet 连接不佳时),您的应用很容易被寻找冻结应用的看门狗进程杀死,等等。

因此,与其执行 segue 并让 shouldPerformSegue 尝试等待网络响应以查看是否可以继续,不如反过来做:您可以编写执行查询的代码,如果一切正常,然后才以编程方式启动 segue。

【讨论】:

  • 我按照你说的做了什么:我创建了一个新按钮。在这个按钮上,我调用网络请求......如果它正常,如果它失败,我会显示一个警报。按下确定后,在成功警报上,我得到了放松的 segue。很好...我只是注意到从按下 ok 到关闭视图有一点延迟。
猜你喜欢
  • 2014-10-01
  • 2017-06-02
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 2013-08-06
  • 2017-06-13
  • 2016-09-10
相关资源
最近更新 更多