Saving location coordinates to Core data- Swift 3

5.4k views Asked by At

I want to save location coordinates into Core Data- what is the right way of storing these and retrieving them?

At the moment I am doing this and getting errors:

    var newPlaceCoordinate = CLLocationCoordinate2D()
      var newPlaceLatitude = CLLocationDegrees()
     var newPlaceLongitude = CLLocationDegrees()

I get my coordinates from using Google maps API using the autocomplete widget.

    let newPlaceCoordinate = place.coordinate
  self.newPlaceCoordinate = place.coordinate
    let newPlaceLatitude = place.coordinate.latitude
    print(newPlaceLatitude)
   self.newPlaceLatitude = place.coordinate.latitude
    let newPlaceLongitude = place.coordinate.longitude
    print(newPlaceLongitude)
self.newPlaceLongitude = place.coordinate.longitude

Then to store the coordinates I use:

      let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let newPlace = NSEntityDescription.insertNewObject(forEntityName: "StoredPlace", into: context)
     newPlace.setValue(newPlaceCoordinate, forKey: "coordinate")
    newPlace.setValue(newPlaceLatitude, forKeyPath: "latitude")
    newPlace.setValue(newPlaceLongitude, forKeyPath: "longitude")

And I have the attributes all set as String types. Then to retrieve in my ViewDidLoad I have:

      let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "StoredPlace")

    request.returnsObjectsAsFaults = false
    if let coordinate = result.value(forKey: "coordinate") as? String

           {
                 let latitude = (coordinate as NSString).doubleValue
                    let longitude = (coordinate as NSString).doubleValue
                    let markers = GMSMarker()
                    markers.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
                    markers.icon = GMSMarker.markerImage(with: UIColor.yellow)
                    markers.tracksViewChanges = true
                    markers.map = vwGMap
                }

So this is not working and producing an error of 'attribute: property = "coordinate"; desired type = NSString; given type = NSConcreteValue'. I have a few questions.

How do I save a coordinate data appropriately? Do I save it as a CLLocationDegrees or CLLocationCoordinate2D? How do I convert these objects into NSString or should I be using a different type in my attributes? (I tried changing it to Double or Integer but it also produced errors). I have multiple location coordinates which I would want to store and retrieve from core data.

2

There are 2 answers

5
Matt On BEST ANSWER

If you are going to deal with lots of data, then CoreData is the best bet.

These are my attributes in StorePlace entity, its best to save only latitude and longitude and create coordinates from them when needed in your implementation.

@NSManaged public var newPlaceLatitude: Double
@NSManaged public var newPlaceLongitude: Double

And to insert new data, I will do

class func insert(latitude: Double, longitude: Double) {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managedObjectContext = appDelegate.managedObjectContext

    let entity =  NSEntityDescription.entity(forEntityName: "StoredPlace", in:managedObjectContext)
    let newItem = StoredPlace(entity: entity!, insertInto: managedObjectContext)

    newItem.newPlaceLatitude = latitude
    newItem.newPlaceLongitude = longitude

    do {
        try managedObjectContext.save()
    } catch {
        print(error)
    }
}

After retrieving latitude, longitude you can use coordinate in your implementations as

let newItem = getCoordinateFromCoreData() // your retrieval function
let coordinate = CLLocationCoordinate2D(latitude: newItem.latitude, longitude: newItem.longitude)
1
Arun Gupta On

You need to convert the co-ordinate to double/NSdata type and then store it in CoreData. Use NSKeyedArchiver and NSKeyedUnarchiver to store and retrieve the values. CoreData can't store CLLocation object directly.

// Convert CLLocation object to Data
let newPlaceLatitudeArchived = NSKeyedArchiver.archivedDataWithRootObject(newPlaceLatitude)
//CoreData Piece
newPlace.setValue(newPlaceLatitudeArchived, forKeyPath: "latitude")

// fetch the latitude from CoreData as Archive object and pass it to unarchive to get the CLLocation

let newPlaceLatitudeUnArchived = NSKeyedUnarchiver.unarchiveObjectWithData(archivedLocation) as? CLLocation 

You will need to convert you attribute to binary type in CoreData in this case.