DispatchQueue не обновляет данные в swift - PullRequest
0 голосов
/ 03 февраля 2019

Мне нужно выполнить операцию поиска в 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 голосов
/ 03 февраля 2019

Проблема в том, что callWebAPI является асинхронным (возвращается сразу перед выполнением запроса), поэтому вы немедленно вызываете leave.Вы можете дать этому методу обработчик завершения и вызвать в нем leave.И вы бы также вызывали обновление пользовательского интерфейса в блоке notify для своей группы, а не просто отправляли его.

Проще, просто полностью удалите DispatchGroup и просто обновите свой пользовательский интерфейс в обработчике завершения, который вы предоставляетеcallWebAPI.

Например, дать 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 для заполнениямоделировать объекты напрямую, но это выходит за рамки этого вопроса.

...