views:

451

answers:

3

I have a coredata based iphone app and have an Entity that has latitude and longtitude as properties. How can I return all my entities ordered by distance from the current location? I previosuly did this without coredata writing a sql query, but am new to coredata and can't figure it out. I would like to use the NSFetchedResultsController to pass straight to my tableview.

Any help please?

+1  A: 

Well, here's the problem: when you execute an NSFetchRequest, you can only base the predicate on persistent properties. It seems exceedingly unlikely you would have a persistent property that tracks the distance from the current location.

You could add a transient property to your entity that gives the distance from some globally defined location. You'd have to do a fetch request that gets all the objects, and then order them by this transient property.

If you have a lot of objects, you run the risk of filling up your memory quite quickly. And even if you don't, you'll still end up wasting time fetching objects you're never going to use.

I'm guessing you probably had a nifty SQL SELECT statement that computed the current distance in your previous version. You're not going to be able to replicate that with Core Data.

Alex
I figured that would be the case, although i though maybe i could pass in a sort function that calculated against the lat and long, but it seems you can't. It all sounded too good to be true :-) If I am using SQLLite, I suppose I can bypass coredata and stick with my sql query. thanks.
+1  A: 

I have a similar situation - and although the above is true with regards to not being able to use the NSFetchedResultsController you can still use core data to retrieve your data.

I also used sqlite3 before - and my fetch was done as a series of fetches of increasing bounding box sizes - until a size is reached where I have 'enough' results. In my case I double the latitude and longitude span for every iteration - giving approx. a quadrupling of the area for each iteration.

This method works fine in Core Data too - but as it is also stated above you need to copy the objects into a new array and sort them using your own method after the fetch is done.

Morten Bek Ditlevsen
i think i will end up doing something like that. I guess i will have to do a bit of work instead of getting it all for free :-) using sql directly with coredata is making me feel ill.
A: 

In my experience the best way to do this is to compute the distance of every single entry on first load (or location change) and save that property to CoreData, that way you can easily fetch entries using the distance property.

Here's a code snippet that calculates distance between 2 sets of coordinates:

// I keep this location in memory, as it's the user's current location and it'll be used everytime we need to calculate a distance. c is for current
CLLocation *cLocation = [[CLLocation alloc] initWithLatitude:cLatitude longitude:cLongitude];

// You probably want to put this code inside a loop that goes through every CoreData entry. e is for entry
CLLocation *eLocation = [[CLLocation alloc] initWithLatitude:eLatitude longitude:eLongitude];
double distance = [cLocation distanceFromLocation:eLocation]/1000 // in km
[eLocation release];
Sam V