36
votes

I'm trying to save a location and retrieve the location on a map afterward using Core Location, MapKit and Core Data frameworks.

What I've done is I just made entity named POI and added properties such as latitude (double type), longitude (double type) with few others.

Simply put, my app saves POI with two NSNumbers. (lat and long) but I feel like there must be a smarter way to store CLLocation than that.

cheers.

5

5 Answers

36
votes

What you're doing is fine. You should save the latitude and longitude as doubles in Core Data. When you need to get the information again, get the doubles back from Core Data and construct a CLLocationCoordinate2D struct with a function like CLLocationCoordinate2DMake. There's no built in way to store a location, so storing the latitude and longitude components is fine.

If you're not doing any math operations on the latitude or longitude (finding bounding boxes etc) you could store them as strings. Floats and doubles can change their values slightly, making comparison operations fail.

29
votes

CLLocation implements the NSCoding protocol so you can store them in Core Data as transformable attributes. You can use the default NSKeyedUnarchiveFromData value transformer.

You would just pass the CCLocation object to the managed object attribute and it would serialize it to data and store it as a blob in the SQL store. When you need the location object back it would automatically reverse the process and return to you a fully populated CCLocation object.

That might be the easiest way to get what you want.

19
votes

The "best" way to store it depends on what you want to do with it:

  • If you want the "same" CLLocation, serialize it. NSKeyedUnarchiveFromData is fine.
  • If you just want to search on latitude and longitude, then store those as doubles (and check the "indexed" checkbox).

There's a bunch of additional properties you can save/restore if you do it manually (altitude, horizontalAccuracy, verticalAccuracy, timestamp). There are some more that you can't (speed, heading); CLLocation doesn't provide a suitable init-method and the properties are readonly.

All of the extra properties are useful if you're recording a track. Altitude is useful if you're recording a POI on mountainous terrain ("we still have to climb 100 m"). horizontal/vertical accuracy might be used to represent how big the POI is (e.g. a city might have a "horizontal accuracy" of several km and be displayed as a big circle).

1
votes

You can do this very simply just by setting the Core Data attribute type to Transformable. The default transformer if you leave the Value Transformer Name blank is NSKeyedArchiver which works with most Foundation types such as NSURL and CLLocation.

0
votes

You don't need to use NSNumber to store latitude and longitude points. You can store CLLocation directly to core data instead.

Set up an entity for each CLLocation, it'll be a too-many relation off whatever entity is using location points. Let's call this LocationPoint:

class LocationPoint: NSManagedObject {

@NSManaged var game: NSNumber
@NSManaged var time: NSDate
@NSManaged var location: AnyObject

}

You then set the location property to transformable in the Xcode data model. That's it!

In Objective-c you can actually still declare this LocationPoint property as CLLocation without any errors:

@property (nonatomic, strong) CLLocation *location

More info here.