iosswiftcore-datanscodingmkpolyline

How to store an MKPolyline attribute as transformable in IOS coredata with swift?


What would be the code required to allow the storage of an MKPolyline in CoreData in swift.

So for example if I had one of my core data entities (say "myEntity") for which I wanted to save an MKPolyline, and have added the "polyline" field as transformable, and have set it to "transformable" in xcode. Also have produced NSManagedObject subclass.

myEntity.swift

import UIKit
import CoreData
import MapKit
class myEntity: NSManagedObject {
}

myEntity+CoreDataProperties.swift

import Foundation
import CoreData
extension myEntity {
    @NSManaged var title: String
    @NSManaged var polyline: NSObject? 
}

Question - What code is required to allow this to work?

( I do note this post re objective-c, however I'm struggling to understand/port/get this to work - How do you store data from NSMutable Array in Core Data? )


Solution

  • Archive polyline object and save to Core Data:

        let context = self.fetchedResultsController.managedObjectContext
        let entity = self.fetchedResultsController.fetchRequest.entity!
        let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName(entity.name!, inManagedObjectContext: context)
        let polylineObj = polyline() // For test purpose.
        let polylineData = polylineToArchive(polylineObj)
                newManagedObject.setValue(polylineData, forKey: "polyline")
            context.save()
    

    Unarchive polyline from the NSManagedObject:

        let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
        let data = object.valueForKey("polyline") as! NSData
        let polyline = polylineUnarchive(data)
        log(polyline!)
    

    MKPolyline arhiver and unarchiver functions. As well some helper functions.

    func polylineUnarchive(polylineArchive: NSData) -> MKPolyline? {
        guard let data = NSKeyedUnarchiver.unarchiveObjectWithData(polylineArchive),
            let polyline = data as? [Dictionary<String, AnyObject>] else {
            return nil
        }
        var locations: [CLLocation] = []
        for item in polyline {
            if let latitude = item["latitude"]?.doubleValue,
                let longitude = item["longitude"]?.doubleValue {
                let location = CLLocation(latitude: latitude, longitude: longitude)
                locations.append(location)
            }
        }
        var coordinates = locations.map({(location: CLLocation) -> CLLocationCoordinate2D in return location.coordinate})
        let result = MKPolyline(coordinates: &coordinates, count: locations.count)
        return result
    }
    
    func polylineToArchive(polyline: MKPolyline) -> NSData {
        let coordsPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.alloc(polyline.pointCount)
        polyline.getCoordinates(coordsPointer, range: NSMakeRange(0, polyline.pointCount))
        var coords: [Dictionary<String, AnyObject>] = []
        for i in 0..<polyline.pointCount {
            let latitude = NSNumber(double: coordsPointer[i].latitude)
            let longitude = NSNumber(double: coordsPointer[i].longitude)
            let coord = ["latitude" : latitude, "longitude" : longitude]
            coords.append(coord)
        }
        let polylineData = NSKeyedArchiver.archivedDataWithRootObject(coords)
        return polylineData
    }
    
    func polyline() -> MKPolyline {
        let locations = [CLLocation(latitude: 37.582691, longitude: 127.011186), CLLocation(latitude: 37.586112,longitude: 127.011047), CLLocation(latitude: 37.588212, longitude: 127.010438)]
        var coordinates = locations.map({(location: CLLocation) -> CLLocationCoordinate2D in return location.coordinate})
        let polyline = MKPolyline(coordinates: &coordinates, count: locations.count)
        return polyline
    }
    
    func log(polyline: MKPolyline) {
        let coordsPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.alloc(polyline.pointCount)
        polyline.getCoordinates(coordsPointer, range: NSMakeRange(0, polyline.pointCount))
        var coords: [Dictionary<String, AnyObject>] = []
        for i in 0..<polyline.pointCount {
            let latitude = NSNumber(double: coordsPointer[i].latitude)
            let longitude = NSNumber(double: coordsPointer[i].longitude)
            let coord = ["latitude" : latitude, "longitude" : longitude]
            coords.append(coord)
        }
        print(coords)
    }