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

标签 swift asynchronous request swiftui completionhandler

我有一个函数,可以调用 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?

有谁知道为什么我上面的代码片段可以让一切正常工作?

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

最佳答案

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

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

最初我问,有谁知道在所有请求完成后如何更新我的@EnvironmentObject?

有人知道为什么我上面的代码片段能让一切正常工作吗?我只是想了解我在做什么,也许有人可以学到一些东西,如果他们发现这个

关于swift - 如何在 SwiftUI 中异步请求完成后调用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59619673/

相关文章:

ios - 在 iOS 中使用 Microsoft App Center 环境变量

Swift - 如何使用 iOS 图表设置 x 轴以显示每小时间隔

ios - 将数据从 firebase 获取到 UITableViewController - swift

java - 单击 ListView 行时如何处理 JSON 的 NULL 结果?

python - 我如何使用请求库在python中下载所有类型的文件

javascript - 如何使用查询字符串 promise GET 请求?

php - 405 方法不允许 json 数据不发布

ios - 使用 UINavigationBar 后退按钮浏览所需的 View (同时跳过某些 View )

linux - 事件驱动和异步有什么区别?在 epoll 和 AIO 之间?

c# - Lazy<> 和 Task<> 可以组合起来推迟数据库查找吗?