DispatchQueue不会快速更新数据

时间:2019-02-03 17:13:38

标签: swift asynchronous search nsoperation

我需要在Swift中执行搜索操作,并且需要使用UISearchbar。

在textDidChange事件上,我需要调用网络api,解析响应,然后更新数组,然后开始对更新后的数组进行搜索。

但不确定我的代码是否起作用。

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

    let group = DispatchGroup()
    group.enter()
    // Perform some asynchronous operation
    let queue1 = DispatchQueue(label: "abc")
    queue1.async {
        self.callWebAPI() // This function calls the web api and parses it’s response
        group.leave()
    }

    DispatchQueue.global(qos: .utility).async {
        DispatchQueue.main.async {
            self.filteredCountry = self.arrCountry.filter({$0.name.prefix(searchText.count) == searchText})
            self.searching = true
            self.tableView.reloadData()
        }
    }
}

func callWebAPI() {
    let urlString = URL(string: "https://restcountries.eu/rest/v2/all")
    if let url = urlString {
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if error != nil {
                print(error!)
            } else {
                if let usableData = data {
                    do{
                        //here dataResponse received from a network request
                        let jsonResponse = try JSONSerialization.jsonObject(with:
                            data!, options: [])
                        print(jsonResponse) //Response result

                        guard let jsonArray = jsonResponse as? [[String: Any]] else {
                            return
                        }


                        print(jsonArray)

                        print("done")

                    } catch let parsingError {
                        print("Error", parsingError)
                    }

                }
            }
        }
        task.resume()
    }

}

请指导我上面的代码,以免我错在哪里

1 个答案:

答案 0 :(得分:0)

问题在于callWebAPI是异步的(它在请求完成之前立即返回),因此您正在立即调用leave。您可以为该方法提供完成处理程序,然后在其中调用leave。而且,您还可以在notify块中为您的组调用UI更新,而不仅仅是调度它。

更容易,只需完全退休DispatchGroup,然后在提供给callWebAPI的完成处理程序中更新UI。

例如,给callWebAPI一个完成处理程序:

func callWebAPI(completionHandler: @escaping ([[String: Any]]?, Error?) -> Void) {
    let urlString = URL(string: "https://restcountries.eu/rest/v2/all")
    if let url = urlString {
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let data = data, error == nil else {
                completionHandler(nil, error)
                return
            }

            do {
                let jsonResponse = try JSONSerialization.jsonObject(with:
                    data)

                completionHandler(jsonResponse as? [[String: Any]], nil)
            } catch let parsingError {
                completionHandler(nil, parsingError)
            }
        }
        task.resume()
    }
}

然后,您可以消除调度组,全局队列(因为它已经是异步方法,因此不需要从后台队列中调用它)等等,并且简化为:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    callWebAPI { jsonResponse, error in
        guard let jsonResponse = jsonResponse, error == nil else {
            print("Error:", error ?? "Response was not correct format")
            return
        }

        print(jsonResponse)

        // Note, you don’t appear to be using `jsonResponse` at all,
        // so I presume you’d update the relevant model objects.

        DispatchQueue.main.async {
            self.filteredCountry = self.arrCountry.filter({$0.name.prefix(searchText.count) == searchText})
            self.searching = true
            self.tableView.reloadData()
        }
    }
}

顺便说一句,如今,我们使用JSONDecoder解析JSON以直接填充模型对象,但这超出了此问题的范围。