How to store CLLocation using Core Data (iPhone)?
Asked Answered
B

5

34

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.

Billionaire answered 26/9, 2010 at 8:55 Comment(0)
K
36

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.

Kirkman answered 26/9, 2010 at 9:57 Comment(5)
Thanks nevan, actually I saved those coordinates values in NSString as well for displaying in UILabel. I do have plan to do some math with coordinates but I didn't know that " Floats and doubles can change their values slightly, making comparison operations fail." which makes me back to the original question with slight change; If you need to calculate distance and compare, what is the best way to store CLLocation coordinate values using Core Data?Billionaire
If you're doing some calculation on them, like finding all latitudes greater than 12.34, I'd store them as floats or doubles. Just don't rely on the float value being exactly the same between storing it and fetching it. If you want to make sure the value doesn't change (even by a tiny fraction) use decimal. I'm just not sure how fast it is to do math with decimal types. Here's a link: #159755Kirkman
If you need to store numerical values with great precision and perform operations on them you should use NSDecimal number. Use a value transformer to store them in Core Data. However, I think that would be overkill in this case . Floats and doubles can change values but only at the far extremes of their precision. Latitude/Longitude only require at most 4 decimal places to the right so you can simply control your significant digits to perfectly store and retrieve those values with floats.Interdigitate
@TechZen: This is my feeling too. I use floats in an SQLite database to map shop positions and the accuracy is more than enough for that. If I was mapping earthworm migrations I might use something more accurate.Kirkman
Ugh, no. CLLocation/CLLocationCoordinate2D/CLLocationDegrees use doubles; if you don't want values to "change" then keep them as doubles. Converting between double and NSDecimal does lose precision. Somehow people have the mistaken impression that NSDecimal is perfect; it's not. It's decimal floating point instead of binary floating point.Multivibrator
I
29

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.

Interdigitate answered 26/9, 2010 at 14:55 Comment(2)
If the data is serialized, you won't be able to get the locations within a bounding box without fetching every location from the store.Kirkman
might be easy but can't query when stored in that format.Waylen
M
19

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).

Multivibrator answered 26/9, 2010 at 15:43 Comment(1)
You can now, in 2020, restore all but floor level.Satellite
C
1

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.

Clotho answered 3/2, 2015 at 16:10 Comment(0)
I
0

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.

Iconoduly answered 16/10, 2015 at 21:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.