如何解决SwiftUI 奇怪的 MapKit makeUIView 行为
我有一个 SwiftUI 应用程序,其中包含带有注释和多段线叠加的地图 在高速公路上。我使用 Core Data 来存储 Waypoint 结构来配置折线。 多个航点构成一次旅行。
该应用程序是基本的主/细节样式,带有一个行程列表和一个 DetailView 显示带有叠加层的地图。作为该过程的一部分,我计算时间和 每个航段的距离(航点之间)。所有这些都按预期工作 一个非常奇怪的问题。
当我启动应用程序时,第一次旅行以正确的时间正确显示 和距离。然而,当点击第二个 Trip 的 makeUIView 函数时 UIViewRepresentable 被多次调用 - 更奇怪的是,五次。那 显然浪费了互联网资源,并使时间和距离不正确。现在 如果这还不够奇怪,当点击第三个 Trip 时,信息是 正确的。事实上,所有其他的 Trip 都是正确的——无论哪个是第一个, 其他的都是正确的,中间的都是错误的。我的第一个想法是 我在某处有一些奇怪的切换,但我没有。我找不到任何东西 应该要求 makeUIView 被调用五次,当然不是每隔一次。
这是DetailView的代码:
struct DetailMapView: UIViewRepresentable {
let kAppDelegate = UIApplication.shared.delegate as! AppDelegate
@Environment(\.presentationMode) var presentationMode
@Observedobject var mdm: MyDefaultsManager
@State var insertSequence : Int = 0
@State var annotations: [MKAnnotation] = []
@State var s: Int64 = 0
@State var directionsArray: [MKDirections] = []
var aTrip: Trip?
@Binding var thumbImage: UIImage
class Coordinator: NSObject,MKMapViewDelegate {
var parent: DetailMapView
init(_ parent: DetailMapView) {
self.parent = parent
parent.mdm.tripTimeAnddistance = "Waiting for servers..."
}
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
parent.mdm.pubCenterCoordinate = mapView.centerCoordinate
}
func mapView(_ mapView: MKMapView,viewFor annotation: MKAnnotation) -> MKAnnotationView? {
//unrelated code that always works
return crsAnnotationView
}//viewfor
func mapView(_ mapView: MKMapView,didSelect view: MKAnnotationView) {
//print("hello - annotation view tapped")
}
func mapView(_ mapView: MKMapView,annotationView view: MKAnnotationView,calloutAccessoryControlTapped control: UIControl) {
//unrelated code that always works
}//annotationView
func mapView(_ mapView: MKMapView,rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKpolylineRenderer(polyline: overlay as! MKpolyline)
renderer.strokeColor = UIColor.blue
renderer.linewidth = 4.0
return renderer
}//rendererFor
}//class coordinator
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> MKMapView {
dispatchQueue.main.async {
self.mdm.totalRoutedistance = 0.0
self.mdm.totalTravelTime = 0.0
self.mdm.callbackdistance = 0.0
self.mdm.callbackTime = 0.0
}
self.mdm.showAddWaypointControls = false
let mapView = MKMapView()
mapView.showsUserLocation = true
mapView.delegate = context.coordinator
mdm.tripTimeAnddistance = "Calculating..."
redrawTheMap2(trip: aTrip,mapView: mapView,callback2: callback2distanceAndTime)
return mapView
}
func updateUIView(_ view: MKMapView,context: Context) {
//no code here
}//updateUIView
func doOneWaypointpolylineCallback2(view: MKMapView,source: CLLocationCoordinate2D,destination: CLLocationCoordinate2D,callback: @escaping (Double,Double) -> Void) {
var totdist = 0.0
var tottrav = 0.0
for anotation in annotations {
view.deselectAnnotation(anotation,animated: false)
}
view.removeAnnotations(annotations)
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: source))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: destination))
request.requestsAlternateRoutes = false
request.transportType = mdm.walkDirections ? .walking : .automobile
let directions = MKDirections(request: request)
directions.calculate { response,error in
guard let unwrappedResponse = response else {
if let error = error {
print("Direction calulation Failed: \(error.localizedDescription)")
self.mdm.tripTimeAnddistance = "The servers Could not be reached. Please try later."
//throw an alert here to tell the user
}
return
}//guard
let route = unwrappedResponse.routes[0]
view.addOverlay(route.polyline)
tottrav += route.expectedTravelTime
totdist += route.distance
self.mdm.totalRoutedistance += totdist
self.mdm.totalTravelTime += tottrav
callback(self.mdm.totalRoutedistance,self.mdm.totalTravelTime)
}
}//doOneWaypoint polyline Callback2
func resetMapView(mapView: MKMapView,withNew directions: MKDirections) {
mapView.removeOverlays(mapView.overlays)
dispatchQueue.main.async {
self.directionsArray.append(directions)
let _ = self.directionsArray.map { $0.cancel() }
self.directionsArray.removeAll()
}
}
func chooseTransportType() -> MKDirectionsTransportType {
//unrelated code that always works
}//chooseTransportType
func updatedistanceAndTimeTupleSingle(distance : Double,time : Double) {
self.mdm.callbackdistance += distance
self.mdm.callbackTime += time
let totaldistance = NU.formatdistance(distanceMeters: distance,isMetric: self.mdm.metricdistance)
let totalTime = NU.formatTime(timeInSec: time)
self.mdm.tripTimeAnddistance = "Combined distance is " + totaldistance +
" and combined travel time is " + totalTime + "\n"
}//update distanceAndTime Tuple
func redrawTheMap2(trip: Trip?,mapView: MKMapView,callback2: @escaping (Double,Double) -> Void) {
mdm.redrawTheMap2Count += 1
print("udm.redrawTheMap2Count is \(mdm.redrawTheMap2Count)")
mapView.removeAnnotations(mapView.annotations)
mapView.removeOverlays(mapView.overlays)
guard let detail = aTrip else { return }
for waypoint in detail.waypoints {
let wp = waypoint as! Waypoint
//print("waypoint sequence number = \(wp.sequence)")
let coordinate = CLLocationCoordinate2D(latitude: (waypoint as! Waypoint).latitude,longitude: (waypoint as! Waypoint).longitude)
//make an annotation from the waypoint information
let annotation = AnnotationPin(wp: wp,title: "WP" + String(wp.sequence),subtitle: wp.name ?? "Subtitle",coordinate: coordinate)
//this is the only place annotations are added to the detail view
mapView.addAnnotation(annotation)
}//for in
let wpArray = Array(detail.waypoints).sorted(by: { ($0 as AnyObject).sequence < ($1 as AnyObject).sequence })
var wpSourceSequence = 0
var wpDestinationSequence = 1
//for callback 2
self.mdm.callbackdistance = 0.0
self.mdm.callbackTime = 0.0
//callback 2 above
while wpDestinationSequence < wpArray.count {
doOneWaypointpolylineCallback2(view: mapView,source: CLLocationCoordinate2D(latitude: (wpArray[wpSourceSequence] as! Waypoint).latitude,longitude: (wpArray[wpSourceSequence] as! Waypoint).longitude),destination: CLLocationCoordinate2D(latitude: (wpArray[wpDestinationSequence] as! Waypoint).latitude,longitude: (wpArray[wpDestinationSequence] as! Waypoint).longitude),callback: updatedistanceAndTimeTupleSingle)
wpSourceSequence += 1
wpDestinationSequence += 1
}//while
callback2(self.mdm.callbackdistance,self.mdm.callbackTime)
}//redraw The Map 2
func callback2distanceAndTime (distance : Double,time : Double) {
print("TryYo \(distance) and TryYo \(time)")
}
}
顺便说一句 - 我前段时间将这个应用程序发布到了 App Store(还有几个 之前的 iOS 和 Xcode 版本),我相信该应用当时的行为符合预期。
任何指导将不胜感激。 Xcode 12.5 iOS 14.5
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。