Search code examples
swiftmapkitmkmapviewcombinemkmapviewdelegate

How to draw MKPolyline with moving points?


So I have an app which is receiving every second some latitude and longitude data from a websocket.

What I'm trying to do is draw a path on my map (MKMapView) every time I receive a new position. The code is working so far, but after approximately 30 minutes of the app running it starts to increase the RAM memory consumed and the processor usage % increase to 300% and the app starts freezing.

I think I need a way to re-write the usage of MKPolyline in a more performative way. Maybe I'm writing the overlay too many times?

basically, my question is:

How can I draw a path on the map, while receiving the coordinates of this path every second?

Here's how I'm doing it:

View Controller:

var polyline: MKPolyline?

override func viewDidLoad() {
    super.viewDidLoad()
    setupBindings()
    mapView.delegate = self
    mapView.addAnnotation(viewModel.aircraftLocation)
}

func setupBindings() {
   //This code is triggered every second with new latitude and longitude
    viewModel.$simulationData.sink { [weak self] simData in
        guard let simData, let self else { return }
        DispatchQueue.main.async {
            self.LatitudeLbl.text = String(format: "Lat: %.5f", simData.latitude)
            self.longitudeLbl.text = String(format: "Long: %.5f", simData.longitude)
            self.polyline = MKPolyline(coordinates: &self.viewModel.aircraftPath, count: self.viewModel.aircraftPath.count)
            if let polyline = self.polyline {
                self.mapView.addOverlay(polyline)
            }
        }
    }.store(in: &viewModel.subscriptions)
            
}

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    guard let overlay = overlay as? MKPolyline else {
        return MKOverlayRenderer()
    }
    let render = MKPolylineRenderer(polyline: overlay)
    render.strokeColor = .purple
    render.lineWidth = 2
    return render
}

View Model:

@Published public var simulationData: SimulationData?

    func didReceiveSimulationUpdate(simulation: SimulationData) {
        //add the coordinates to the array where the map will read and draw the path
        aircraftPath.append(simulation.aircraft.location)
        
        DispatchQueue.main.async {
            UIView.animate(withDuration: 0.3) {
                self.simulationData = simulation
                self.aircraftLocation.coordinate = simulation.aircraft.location
            }
        }
        
    }

Solution

  • So to fix this issue, all I had to do is create a logic where it has kind of a "buffer" of points. Whenever I have 2 new points I draw a new line between them.