How to store CLLocation using Core Data (iPhone)?

22,354

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

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.

Share:
22,354
bicbac
Author by

bicbac

Updated on October 17, 2020

Comments

  • bicbac
    bicbac over 3 years

    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.

  • bicbac
    bicbac over 13 years
    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?
  • nevan king
    nevan king over 13 years
    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: stackoverflow.com/questions/159255/…
  • TechZen
    TechZen over 13 years
    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.
  • nevan king
    nevan king over 13 years
    @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.
  • nevan king
    nevan king over 13 years
    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.
  • tc.
    tc. over 13 years
    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.
  • malhal
    malhal over 8 years
    might be easy but can't query when stored in that format.
  • zrfrank
    zrfrank almost 4 years
    You can now, in 2020, restore all but floor level.