【发布时间】:2020-01-06 22:11:52
【问题描述】:
我有一个函数调用 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 充当“事实来源”。
我尝试使用下面的代码完成此操作,但不断收到错误 - “不允许从后台线程发布更改;请确保从主线程发布值(通过诸如接收(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,但我不知道该怎么做。
编辑 - 按照 cmets 的要求提供我的 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 请求中使用这个 sn-p 代码,它解决了我的问题,虽然我不明白为什么我需要这样做
DispatchQueue.main.async {
self.venueData.venuesdataarray.append(RESPONSE_DETAILS_HERE)
}
最初我问过,有谁知道我如何在所有请求完成后更新我的@EnvironmentObject?
有人知道为什么我上面的 sn-p 可以让一切正常吗?
我只是想了解我在做什么,如果他们发现这个,也许有人可以学到一些东西
【问题讨论】:
-
你能展示你的场地数据吗?
-
@Ernist Isabekov 是的,我在上面的编辑中包含了它
标签: swift asynchronous request swiftui completionhandler