Как вызвать функцию после asyn c запросов fini sh в SwiftUI? - PullRequest
0 голосов
/ 07 января 2020

У меня есть функция, которая вызывает 2 типа запросов API, чтобы получить кучу данных, которые мне нужны в моем приложении. В функции я делаю запрос местоположений, затем для каждого местоположения в ответе я делаю разные запросы, чтобы получить подробную информацию об этом конкретном c местоположении. (например, если запрос 1 возвращает 20 местоположений, мой второй запрос вызывается 20 раз, по одному разу для каждого местоположения)

Мой код функции здесь:

    func requestAndCombineGData(location: CLLocation, radius: Int) {
    // Clears map of markers
        self.mapView.clear()


        // Calls 'Nearby Search' request 
        googleClient.getGooglePlacesData(location: location, withinMeters: radius) { (response) in
            print("Made Nearby Search request. Returned response here:", response)

            // loops through each result from the above Nearby Request response
            for location in response.results {

                // Calls 'Place Details' request
                self.googleClient.getGooglePlacesDetailsData(place_id: location.place_id) { (detailsResponse) in
                    print("GMV returned - detailsResponse.result - ", detailsResponse.result)

                }

            }            
        }

    }

Функции запроса, на которые я ссылаюсь выше, здесь :

    func getGooglePlacesData(location: CLLocation, withinMeters radius: Int, using completionHandler: @escaping (GooglePlacesResponse) -> ())  {

        for category in categoriesArray {

            let url = googlePlacesNearbyDataURL(forKey: googlePlacesKey, location: location, radius: radius, type: category)

            let task = session.dataTask(with: url) { (responseData, _, error) in
                if let error = error {
                    print(error.localizedDescription)
                    return
                }

                guard let data = responseData, let response = try? JSONDecoder().decode(GooglePlacesResponse.self, from: data) else {
                    print("Could not decode JSON response")
                    completionHandler(GooglePlacesResponse(results:[]))
                    return
                }


                if response.results.isEmpty {
                    print("GC - response returned empty", response)
                } else {
                    print("GC - response contained content", response)
                    completionHandler(response)
                }


            }
            task.resume()
        }

    }




    func getGooglePlacesDetailsData(place_id: String, using completionHandler: @escaping (GooglePlacesDetailsResponse) -> ())  {

        let url = googlePlacesDetailsURL(forKey: googlePlacesKey, place_ID: place_id)

        let task = session.dataTask(with: url) { (responseData, _, error) in
            if let error = error {
                print(error.localizedDescription)
                return
            }

            guard let data = responseData, let detailsResponse = try? JSONDecoder().decode(GooglePlacesDetailsResponse.self, from: data) else {
                print("Could not decode JSON response. responseData was: ", responseData)
                return
            }
            print("GPD response - detailsResponse.result: ", detailsResponse.result)


            completionHandler(detailsResponse)


        }
        task.resume()

    }

После того, как я получу все данные, которые я запрашиваю (или даже когда данные поступают), я хотел бы добавить его в @EnvironmentObject (массив), который я настроил в моем SceneDelegate.swift файл. Я использую данные в нескольких местах в моем приложении, поэтому @EnvironmentObject служит «источником правды».

Я пытался выполнить это, используя приведенный ниже код, но продолжаю получать ошибку - "Публикация изменений из фоновых потоков не допускается; не забудьте опубликовать sh значения из основного потока (через операторы, такие как receive (on :)) при обновлении модели. "

    func requestAndCombineGData(location: CLLocation, radius: Int) {
    // Clears map of markers
        self.mapView.clear()


        // Calls 'Nearby Search' request 
        googleClient.getGooglePlacesData(location: location, withinMeters: radius) { (response) in
            print("Made Nearby Search request. Returned response here:", response)

            // loops through each result from the above Nearby Request response
            for location in response.results {

                // Calls 'Place Details' request
                self.googleClient.getGooglePlacesDetailsData(place_id: location.place_id) { (detailsResponse) in
                    print("GMV returned - detailsResponse.result - ", detailsResponse.result)


                // THIS IS WHERE I TRY TO UPDATE MY @ENVIROMETOBJECT
                self.venueData.venuesdataarray.append(detailsRespose.result)


                }

            }            
        }

    }

Я считаю, что мне нужно чтобы убедиться, что запросы завершены, ТОГДА попробуйте обновить мой @EnvironmentObject, но я не знаю, как это сделать.


РЕДАКТИРОВАТЬ - предоставляя мою структуру VenueData, как было запрошено в комментариях:

struct VenueData : Identifiable {

    var id = UUID()
    var name : String
    var geometry : Location?
    var rating : String?
    var price_level : String?
    var types : [String]?
    var formatted_address : String?
    var formatted_phone_number : String?
    var website : String?
    var photo_reference : String?


    enum CodingKeysDetails : String, CodingKey {
        case geometry = "geometry"
        case name = "name"
        case rating = "rating"
        case price_level = "price_level"
        case types = "types"
        case opening_hours = "opening_hours"
        case formatted_address = "formatted_address"
        case formatted_phone_number = "formatted_phone_number"
        case website = "website"
    }


    // Location struct
    struct Location : Codable {

        var location : LatLong

        enum CodingKeys : String, CodingKey {
            case location = "location"
        }


        // LatLong struct
        struct LatLong : Codable {

            var latitude : Double
            var longitude : Double

            enum CodingKeys : String, CodingKey {
                case latitude = "lat"
                case longitude = "lng"
            }
        }
    }



}


class VenueDataArray: ObservableObject {
    @Published var venuesdataarray : [VenueData] = [
        VenueData(name: "test_name")
    ]
}

Редактирование решения - я попытался использовать этот фрагмент кода во втором запросе API, и это решило мою проблему, хотя я не понимаю, почему мне нужно это сделать

    DispatchQueue.main.async {
        self.venueData.venuesdataarray.append(RESPONSE_DETAILS_HERE)
    }

Изначально я спрашивал: кто-нибудь знает, как я могу обновить мой @EnvironmentObject после завершения всех запросов?

Кто-нибудь знает, почему фрагмент кода у меня есть? Он заставляет все работать?

Мне бы просто хотелось понять, что я делаю, и, может быть, кто-то мог бы что-то узнать, если бы нашел это

Ответы [ 2 ]

1 голос
/ 10 января 2020

Есть несколько вещей, которые вы не можете успешно сделать из фонового потока. Некоторые из них (например, изменения содержимого UIKit) не генерируют ошибку, но молча терпят неудачу, что хуже. Вам повезло, что вы получили относительно конкретное сообщение об ошибке c.

Сообщение об ошибке состояло в том, что вы не можете опубликовать sh изменения из фонового потока, и вам необходимо сделать это из основного потока .

Обертывание вашего приложения внутри "DispatchQueue.main.asyn c" заставляет эту строку кода выполняться в главном потоке.

Вот и все. Вероятно, это можно было бы объяснить более кратко.

0 голосов
/ 08 января 2020

Я пытался использовать этот фрагмент кода во втором запросе API, и это решило мою проблему, хотя я не понимаю, почему мне нужно это сделать

DispatchQueue.main.async {
    self.venueData.venuesdataarray.append(RESPONSE_DETAILS_HERE)
}

Первоначально я спросил: Кто-нибудь знает, как я могу обновить свой @EnvironmentObject после того, как все запросы завершены?

Кто-нибудь знает, почему у моего фрагмента выше все работает? Id просто хотел бы понять, что я делать, и, возможно, кто-то может что-то узнать, если они найдут это

...