How to save a MKGeodesicPolyline?

Hello.


I have an application where a map is located on one of the tabs. The application tracks movement of an object and draws a polyline of such movement. The code is like this:


var polylineFlight : MKGeodesicPolyline!

func drawFlightPath(Latitude latitude: String?, Longitude longitude: String?)
    {
        // Extract a saved polyline
        let defaultsLoad = UserDefaults.standard
        let polylineFlightData = defaultsLoad.object(forKey: "PolylineFlightData") as? NSData
        if let polylineFlightData = polylineFlightData
        {
            self.polylineFlight = NSKeyedUnarchiver.unarchiveObject(with: polylineFlightData as Data) as! MKGeodesicPolyline!
        }
  
        if appSingleton.isConnectionAvailableShared == true
        {
            if self.previousLatitude == nil && self.previousLongitude == nil && latitude != nil && longitude != nil
            {
                self.previousLatitude = latitude!
                self.previousLongitude = longitude!
            }
          
            else if self.previousLatitude != nil && self.previousLongitude != nil && latitude != nil && longitude != nil
            {
                if self.previousLatitude == latitude && self.previousLongitude == longitude
                {
              
                }
                else
                {
                    var routeCoordinates = [CLLocationCoordinate2D](repeating: CLLocationCoordinate2D(), count: 2)
            
                    var currentCoordinates = CLLocationCoordinate2D()
                    var previousCoordinates = CLLocationCoordinate2D()
              
                    let currentLatitudeDouble : Double? = Double(latitude!)!
                    let currentLongitudeDouble : Double? = Double(longitude!)!
                    let previousLatitudeDouble : Double? = Double(self.previousLatitude!)!
                    let previousLongitudeDouble : Double? = Double(self.previousLongitude!)!
              
                    if  currentLatitudeDouble != nil &&
                        currentLongitudeDouble != nil &&
                        previousLatitudeDouble != nil &&
                        previousLongitudeDouble != nil
                    {
                        currentCoordinates = CLLocationCoordinate2DMake(currentLatitudeDouble!.roundTo(Places: 8), currentLongitudeDouble!.roundTo(Places: 8))
                        previousCoordinates = CLLocationCoordinate2DMake(previousLatitudeDouble!.roundTo(Places: 8), previousLongitudeDouble!.roundTo(Places: 8))
                  
                        routeCoordinates[0] = previousCoordinates
                        routeCoordinates[1] = currentCoordinates
                  
                        let polyline = MKGeodesicPolyline(coordinates: routeCoordinates, count: routeCoordinates.count)
                        polyline.title = "flight"
                  
                        self.polylineFlight = polyline;
                  
                        self.previousLatitude = latitude
                        self.previousLongitude = longitude
                  
                        if appSingleton.mapView != nil {appSingleton.mapView.add(polyline)}
                  
                        let polylineFlightDataSave = NSKeyedArchiver.archivedData(withRootObject: self.polylineFlight )
                        defaultsLoad.set(polylineFlightDataSave, forKey: "PolylineFlightData")
                    }
                }
            }
        }
    }


The problem is that whenever I switch to another tab, the current polyline disappears and a new one begins being drawn. I would like to save the polyline as a NSData using UserDefaults. However, this is not possible since it crashes on line 57 with uncaught exception of type NSException. Is there a way to save a polyline to preserve it after switching tabs?


Thanks a lot!

Accepted Reply

Yes, store the latitude and longitude individually, such as in a dictionary with keys to identify the 4 values you are tracking (latitude and longitude for both the current and previous locations).

Replies

A better way to do this is to store the latitude and longitude for the two end points explicitly, and to use that data to create a new MKGeodesicPolyline. However, what's your actual problem? You mention there's a problem in having it redraw when you switch tabs - are you just trying to prevent the polyline from redrawing? If so, creating a new polyline every time won't solve that problem, because the new polyline will also need to be drawn once added to the map.

Thank you, edford.


Changed the code to save the coordinates as Data:


var flightPathCoordinates = [CLLocationCoordinate2D]()

func drawFlightPath(Latitude latitude: String?, Longitude longitude: String?)
    {
        if appSingleton.isConnectionAvailableShared == true
        {
                // Code as above...
                       // Appending an array of CLLocationCoordinate2D
                        self.flightPathCoordinates.append(currentCoordinates)
                    
                        let defaultsLoad = UserDefaults.standard
                        let flightPathData = NSKeyedArchiver.archivedData(withRootObject: self.flightPathCoordinates)
                        defaultsLoad.set(flightPathData, forKey: "FlightPathData")
                    }
                }
            }
        }
    }


Same problem. An array of type [CLLocationCoordinate2D] cannot be saved as Data. Should there be a different approach?


The idea is to extract coordinates from the Data and recreate a polyline from these coordinates while continuing to draw the polyline as new data comes from the server.


EDIT: Another issue is that usage of memory (as tracked by XCode using a real device) is increaing every time I switch from one tab to another. This is VERY frustrating. For example, I open the app and it uses 100 MB of memory. I select a tab with the map, the app is now using 280 MB. Fine. I go to another tab, now the app is using 260 MB. Go back to the Map tab, it becomes 320-340 MB. And everytime I select a different tab, the memory is dropping a bit but then increases after I go back to the Map tab. After going back and forth 20-30 times, the memory used totals 700-800 MB. Why???


Thank you.

Yes, store the latitude and longitude individually, such as in a dictionary with keys to identify the 4 values you are tracking (latitude and longitude for both the current and previous locations).

Thank you, I will try and report.Could you also please see my edit about the memory used?


Cheers.

That could happen if the map is being panned, zoomed or any similar actions which load in more data to the map. However, without more details, it's hard to say if there aren't things that you can alter in your code to improve this situation. Discussing those details will be difficult in this forum format due to the need to see code and trace files.


Two things you can do:

1. Create a focused sample with the minimal amount of code needed to reproduce the issue. Ideally this project will start with a new, empty Xcode project to which you add the necessary code. This focuses on the important code paths and may require you to perform additional debugging to extract the relevant code, but can help you isolate the cause.


2. Profile and understand the overall memory footprint of your app. Tech Note 2434 “Minimizing your app’s Memory Footprint” is a good starting point.


If after doing this work you still have questions, please open a Technical Support Incident and include the focused sample and the Instruments trace file from the sample app so we can talk about the specifics in your code.

I understand, edford.


By the way, I have also solved the original issue of saving a polyline using your suggestion. Thank you so much!