iosswiftcore-datamapboxmglmapview

Swift - How to store MGLMapView in Core Data to display it on table view?


Hey guys I'm making a running app and I'm having trouble in saving my MGLMapView, that contains the ploylines drawn from the user running, in Core Data. I'm not getting any errors but decoding returns an empty MGLMapView with no ploylines as if it was just instantiated. When the user saves his/her run, it stores all of the information and display it in a tableView. I'm storing my mapView and my pointsArray (Which contains all the CllocationCoordinates2D created by the user) in a class called mapViewStore as you can see here.

My entity and attributes

The class conforms to NSCoding so it has no problem in encoding and decoding mapView and the pointsArray. I had to break down the coordinates since I can't encode CllocationCoordinate2D in it's entirety.

import UIKit
import Mapbox
import MapKit
import CoreLocation

class MapViewStore: NSObject, NSCoding {

    var mapView: MGLMapView!
    var pointsArray: [CLLocationCoordinate2D] = []
    var latArray: [Double] = []
    var lonArray: [Double] = []
    init(mapView: MGLMapView, pointsArray: [CLLocationCoordinate2D]) {

        self.mapView = mapView
        self.pointsArray = pointsArray
    }

    required init(coder aDecoder: NSCoder) {
        self.mapView = aDecoder.decodeObject(forKey: "mapView") as? MGLMapView
        self.latArray = aDecoder.decodeObject(forKey: "latArray") as! [Double]
        self.lonArray = aDecoder.decodeObject(forKey: "lonArray") as! [Double]

        for i in 0..<lonArray.count {
            let coordinate = CLLocationCoordinate2D(latitude: latArray[i], longitude: lonArray[i])
            pointsArray.append(coordinate)
        }
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(mapView, forKey: "mapView")

        for i in 0..<pointsArray.count {
            latArray.append(pointsArray[i].latitude)
            lonArray.append(pointsArray[i].longitude)
        }
        aCoder.encode(latArray, forKey: "latArray")
        aCoder.encode(lonArray, forKey: "lonArray")
    }

}

Correct if i'm wrong but what I believe is going on here is that when I encode MGLMapView, it converts it to a NSObject and loses all of it's information. So when I convert it back to MGLMapView I get a empty map. Is there a way to avoid this? Maybe store the polylines? Though I might run into the same problem if I do.

I could just recreate the polylines on the mapView with pointsArray but the performance will take a hit.

EDIT: To the people whose viewing this now. Don’t do this. I wanted to create a mapView inside of a table cell which is a very bad idea. Instead take a snapshot and save the image. I’m just learning that now.


Solution

  • What's more likely is that MGLMapView simply doesn't encode the poly lines as part of its NSCoding methods. UIView conforms to NSCoding, so all of its subclasses inherit that. But that doesn't mean all of them add everything necessary to be fully encoded/decoded. A look at the source code for MGLMapView shows that it doesn't implement encodeWithCoder, which is almost certainly the explanation.

    It's very unusual to save a view object to your data model, whether with Core Data or any other option. You'll need to re-create the view state from model objects. That could be your existing pointsArray. It looks like MGLPolyLine encodes its points, so you could use it via NSCoding if you like.