如何在SwiftUI中完成异步请求后如何调用函数?

问题描述 投票:0回答:2

我有一个函数,它调用两种类型的api请求来获取我的应用程序中需要的一堆数据。在函数中,我请求位置,然后在响应中为每个位置请求一个不同的请求,以获取该特定位置的详细信息。 (例如,如果请求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()

    }

[在获得所有我要的数据之后(甚至当数据传入时),我想将其附加到我在SceneDelegate.swift文件中设置的@EnvironmentObject(数组)中。我在应用程序的多个位置使用了数据,因此@EnvironmentObject充当“真理的来源”。

我尝试使用下面的代码完成此操作,但仍然会收到错误-“不允许从后台线程发布更改;请确保在模型上从主线程发布值(通过诸如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吗?

有人知道为什么我上面的代码片段使一切正常吗?

Id只是想了解我在做什么,如果有人发现了这个,也许有人可以学到一些东西

我有一个函数,它调用两种类型的api请求来获取我的应用程序中需要的一堆数据。在函数中,我请求一个位置,然后对于响应中的每个位置,我都做出不同的...

swift asynchronous request swiftui completionhandler
2个回答
1
投票

有一些您无法通过后台线程成功完成的事情。其中一些(例如UIKit内容更改)不会产生错误,但是会静默失败,这更糟。您很幸运收到了相对具体的错误消息。


0
投票

我尝试在我的第二个api请求中使用此代码段,但它解决了我的问题,尽管我不明白为什么需要这样做

© www.soinside.com 2019 - 2024. All rights reserved.