ios - 从 API 检索数据以在数组中使用它们时,如何摆脱“必须从主线程调用 API 方法”问题?迅速
问题描述
我来找你是因为我有以下问题:
我使用“GoogleMaps”cocoapods,我需要使用从 API 获得的纬度、经度和 codeID 在地图中放置几个标记。我将向你们介绍两种情况:一种有效(使用前面提到的 3 个硬编码数组),另一种是我尝试从 API 获取但无论我做什么都会崩溃。好的,第一种情况(有效的)是这个:
import UIKit
import GoogleMaps
class ViewController: UIViewController {
// MARK: - Constants and variables
let lat: Double = 38.739429 // User's Latitude
let lon: Double = -9.137115 // User's Longitude
let zoom: Float = 15.0
// MARK: - Elements in the storyboard
@IBOutlet weak var googleMap: GMSMapView!
// MARK: - ViewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
googleMapsStuff()
}
// MARK: - Google maps method
func googleMapsStuff() {
googleMap.delegate = self
self.googleMap.isMyLocationEnabled = true // User's current position (blue dot on the map)
let arrayLat: [Double] = [38.739, 38.74, 38.741, 38.732, 38.7325, 38.733]
let arrayLon: [Double] = [-9.136, -9.135, -9.134, -9.137, -9.1375, -9.138]
//var arrayCompanyZoneID: [Int] = []
let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: lat, longitude: lon, zoom: self.zoom)
googleMap.camera = camera
for index in 0..<arrayLon.count {
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: arrayLat[index], longitude: arrayLon[index])
marker.title = "Marker number: \(index)"
marker.snippet = "Marker's Lat: \(arrayLat[index]), Marker's Lon: \(arrayLon[index])"
marker.map = self.googleMap
print("Index: \(index)")
}
}
}
问题出现在第二种情况下,当我连接到 API 以获取该数据时尝试填充空数组(它似乎是这样做的)。这是“失败”案例:
struct MyInfo: Codable {
let id: String
let name: String
let x: Double // Longitude
let y: Double // Latitude
let licencePlate: String?
let range: Int?
let batteryLevel: Int?
let seats: Int?
let model: String?
let resourceImageId: String?
let pricePerMinuteParking: Int?
let pricePerMinuteDriving: Int?
let realTimeData: Bool?
let engineType: String?
let resourceType: String?
let companyZoneId: Int
let helmets: Int?
let station: Bool?
let availableResources: Int?
let spacesAvailable: Int?
let allowDropoff: Bool?
let bikesAvailable: Int?
}
class ViewController: UIViewController {
// MARK: - Constants and variables
let lat: Double = 38.739429 // User's Latitude
let lon: Double = -9.137115 // User's Longitude
let zoom: Float = 15.0
var arrayLat: [Double] = [] // [38.7395, 38.739, 38.74, 38.741, 38.732, 38.7325, 38.733]
var arrayLon: [Double] = [] // [-9.1365, -9.136, -9.135, -9.134, -9.137, -9.1375, -9.138]
var arrayCompanyZoneID: [Int] = [] // [1, 2, 3, 4, 5, 6, 7]
// MARK: - Elements in the storyboard
@IBOutlet weak var googleMap: GMSMapView!
// MARK: - ViewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
googleMap.delegate = self
self.googleMap.isMyLocationEnabled = true // User's current position (blue dot on the map)
let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: self.lat, longitude: self.lon, zoom: self.zoom)
googleMap.camera = camera
guard let urlAPI = URL(string: "https://apidev.meep.me/tripplan/api/v1/routers/lisboa/resources?lowerLeftLatLon=38.711046,-9.160096&upperRightLatLon=38.739429,-9.137115") else { return }
let task = URLSession.shared.dataTask(with: urlAPI) {(data, response, error) in
if error == nil {
guard let urlContent = data else { return }
do {
let JSONResult = try JSONDecoder().decode([MyInfo].self, from: urlContent) //JSONSerialization.jsonObject(with: urlContent, options: .mutableContainers)
print("JSON Result:", JSONResult)
for jsonData in JSONResult {
self.arrayLon.append(jsonData.x)
self.arrayLat.append(jsonData.y)
self.arrayCompanyZoneID.append(jsonData.companyZoneId)
}
print("-----------------")
print(type(of: JSONResult))
print("-----------------")
print("ArrayLon:", self.arrayLon)
print("ArrayLat:", self.arrayLat)
print("companyZoneId: ", self.arrayCompanyZoneID)
print("Count zoneid: ", self.arrayCompanyZoneID.count)
print("-----------------")
// MARK: - Place the multiple markers on the map
for index in 0..<self.arrayCompanyZoneID.count {
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: self.arrayLat[index], longitude: self.arrayLon[index])
marker.title = "Marker number: \(index)"
marker.snippet = "Marker's Lat: \(self.arrayLat[index]), Marker's Lon: \(self.arrayLon[index])"
marker.map = self.googleMap
print("Index: \(index)")
}
} catch {
print("JSON processing failed.")
}
} else {
print("Error serializing JSON:", error!)
}
}
task.resume()
}
不管我做什么,控制台总是说:
“由于未捕获的异常'GMSThreadException'而终止应用程序,原因:'必须从主线程调用API方法'”
我也尝试使用该方法
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
但它也说 API 方法大部分是从主线程调用的。
我被困在这里,我在这个问题上投入了几个小时,但它只会一遍又一遍地失败。
我很欣赏你的建议和智慧。
提前致谢。
解决方案
你需要
DispatchQueue.main.async {
// MARK: - Place the multiple markers on the map
for index in 0..<self.arrayCompanyZoneID.count {
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: self.arrayLat[index], longitude: self.arrayLon[index])
marker.title = "Marker number: \(index)"
marker.snippet = "Marker's Lat: \(self.arrayLat[index]), Marker's Lon: \(self.arrayLon[index])"
marker.map = self.googleMap
print("Index: \(index)")
}
}
由于URLSession.shared.dataTask
回调在后台线程中
推荐阅读
- informatica - 抑制消息 - 映射任务无法运行。该任务的另一个实例当前正在运行
- qt - 如何在qml中的chartview绘图区域添加文本
- java - Apache Ignite Spring Data 2.0 解析查询异常
- bixby - bixby 胶囊差异化服务商
- android - api调用时多个视图中的多个进度条
- windows - Windows 关键部分 - 如何完全禁用旋转
- karate - 在空手道中运行一个场景
- c# - 我怎样才能像在终端上一样获取集群信息,但在我的 c# 客户端(stackexchange)上?
- jms - ActiveMQ 如何只删除一些计划的元素
- java - 在 MySQL 中存储自定义级别系统