微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SwiftUI 奇怪的 MapKit makeUIView 行为

如何解决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 举报,一经查实,本站将立刻删除。