Saving Swift CLLocation in CoreData

I am trying to save CLLocation data in Core Data. My property is set as a Transformable object.

Some code example indicates that location data can be saved using this objc converted to NSValue .

 CLLocationCoordinate2D myLocation; NSValue *locationValue = [NSValue valueWithBytes:&myLocation objCType:@encode(CLLocationCoordinate2D)] // then put locationValue into storage - maybe an ObjC collection class or core data etc. 

Retrieving an object from the data warehouse should work using this paradigm.

 CLLocationCoordinate2D myLocation; NSValue *locationValue = // restored from your database or retrieved from your collection class [locationValue getValue:&myLocation]; 

I am trying to extrapolate this idea and grab the entire CLLocation object in NSValue stored in CoreData in order to restore the CLLocation object from storage later.

When testing various methods, I found that nil returns when I try to unpack the CLLocation object from the master data store. I put the CLLocation object in storage using the following:

 //verified that I have a good CLLocation here newManagedObject.setValue(location as CLLocation, forKey: "location") 

Later I will try to deploy CLLocation

 let location = detail.valueForKey("location")! as CLLocation 

But I found that the object is not expanding properly.

cllocation

The expanded object looks like this:

 (CLLocation) location = 0x00007fff59537c90 { ObjectiveC.NSObject = {} } 

Thus, any use of the CLLocation object at this point returns " nil error found ... "

Am I missing something obvious about storing / retrieving CLLocation objects using Swift?

UPDATE

Daniel's answer helped me understand that NSValueTransformer would not work for me, so I went back to the approach I used before. Basically encode the object graph with NSKeyedArchiver. My goal, as always, is to use the simplest possible solution, so I decided not to use subclasses of managed objects, since the required properties are already in the existing CLLocation object. I changed the transformable field to binary data with the check option (Save to external record file). I decided to test this process with minimal changes to the template of the main part.

data-model

Saving a graph of CLLocation objects

 //assuming location is a valid CLLocation and data model has a binary data field let archivedLocation = NSKeyedArchiver.archivedDataWithRootObject(location) newManagedObject.setValue(archivedLocation, forKey: "location") 

Restoring an object graph from a data warehouse

In the main vc, as the default parts are prepared for segue, data is restored through the fetch controller.

 let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject let controller = (segue.destinationViewController as UINavigationController).topViewController as DetailViewController controller.detailItem = object 

In vc details, I expand my object graph using NSKeyedUnarchiver

 var lc = NSKeyedUnarchiver.unarchiveObjectWithData(detail.valueForKey!("location") as NSData) as CLLocation 
+6
source share
3 answers

What you are missing is that NSValue is for storing types, i.e. contiguous blocks of memory, not objects. CLLocation is an object.

To save CLLocation in the master data, you will need to save each of the properties. An alternative is to use an encoder.

+3
source

You will have much less trouble creating a subclass of NSManagedObject for CLLocation objects. Then create methods for saving and retrieving for convenience:

 import Foundation import CoreData import CoreLocation class LocationPoint: NSManagedObject { @NSManaged var latitude: NSNumber! @NSManaged var longitude: NSNumber! @NSManaged var altitude: NSNumber! @NSManaged var timestamp: NSDate! @NSManaged var horizontalAccuracy: NSNumber @NSManaged var verticalAccuracy: NSNumber @NSManaged var speed: NSNumber @NSManaged var course: NSNumber func initFromLocation(location: CLLocation) { self.latitude = location.coordinate.latitude self.longitude = location.coordinate.longitude self.altitude = location.altitude self.timestamp = location.timestamp self.horizontalAccuracy = location.horizontalAccuracy > 0.0 ? location.horizontalAccuracy : 0.0 self.verticalAccuracy = location.verticalAccuracy > 0.0 ? location.verticalAccuracy : 0.0 self.speed = location.speed > 0.0 ? location.speed : 0.0 self.course = location.course > 0.0 ? location.course : 0.0 } func location() -> CLLocation { return CLLocation( coordinate: CLLocationCoordinate2D(latitude: self.latitude.doubleValue, longitude: self.longitude.doubleValue), altitude: self.altitude.doubleValue, horizontalAccuracy: self.horizontalAccuracy.doubleValue, verticalAccuracy: self.verticalAccuracy.doubleValue, course: self.course.doubleValue, speed: self.speed.doubleValue, timestamp: self.timestamp ) } 

You must customize your data model with the entity in accordance with this class.

+5
source

This post is still useful, but a bit outdated.

To save CLLocation, I use:

 let clocation: [CLLocation] let archivedLocation = NSKeyedArchiver.archivedData(withRootObject: clocation) 

And get using the master data:

 let unarchivedLocation = NSKeyedUnarchiver.unarchiveObject(with: (coreDataLocation.value(forKey: "location") as! NSData) as Data) as! CLLocation) 
0
source

Source: https://habr.com/ru/post/977856/


All Articles