Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSSortDescriptor - sort by location

I have a list of geographical locations in Core Data (entity name is "Stops").

I want to sort them by the current location, so I can show the user which locations are nearby. I'm using an NSFetchedResultsController so that the results can be easily displayed in a UITableView.

I am using the following code to attempt this sort:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"stop_lat" ascending:YES comparator:^NSComparisonResult(Stops *obj1, Stops *obj2) {
    CLLocation *currentLocation = locationManager.location;

    CLLocation *obj1Location = [[CLLocation alloc]initWithLatitude:[obj1.stop_lat doubleValue] longitude:[obj1.stop_lon doubleValue]];
    CLLocation *obj2Location = [[CLLocation alloc]initWithLatitude:[obj2.stop_lat doubleValue] longitude:[obj2.stop_lon doubleValue]];

    CLLocationDistance obj1Distance = [obj1Location distanceFromLocation:currentLocation];
    CLLocationDistance obj2Distance = [obj2Location distanceFromLocation:currentLocation];

    NSLog(@"Comparing %@ to %@.\n  Obj1 Distance: %f\n  Obj2 Distance: %f",obj1.stop_name, obj2.stop_name, obj1Distance, obj2Distance);

    if (obj1Distance > obj2Distance) {
        return (NSComparisonResult)NSOrderedDescending;
    }

    if (obj1Distance < obj2Distance) {
        return (NSComparisonResult)NSOrderedAscending;
    }

    return (NSComparisonResult)NSOrderedSame;
}];

NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setEntity:[NSEntityDescription entityForName:[Stops entityName] inManagedObjectContext:context]];

frcNearby = [[NSFetchedResultsController alloc]
          initWithFetchRequest:fetchRequest
          managedObjectContext:context
          sectionNameKeyPath:nil
          cacheName:nil];

NSError *error;
BOOL success = [frcNearby performFetch:&error];
if (error) NSLog(@"ERROR: %@ %@", error, [error userInfo]);

However, my NSFetchedResultsController is just returning all of my items sorted by the key I specified ("stop_lat") rather than sorted by the user's current location.

It looks like my comparator block isn't ever getting called, because the NSLog in there never prints.

What am I missing here?

like image 850
Aaron Brager Avatar asked Dec 21 '22 17:12

Aaron Brager


2 Answers

Objective-C based sort descriptors cannot be used with a fetch request.

From the "Core Data Programming Guide":

... To summarize, though, if you execute a fetch directly, you should typically not add Objective-C-based predicates or sort descriptors to the fetch request. Instead you should apply these to the results of the fetch.

like image 169
Martin R Avatar answered Jan 01 '23 15:01

Martin R


A different take on this would be to have a property on your 'Stop' managedObject called meanSquared (probably an NSDecimalNumber).

When your device lat/long has moved sufficiently to alter the 'nearest Stop' data, then you update all 'Stop' objects with the meanSquared distance (i.e. (yourLat-stopLat)^2+(yourLong-stopLong)^2), then just use 'meanSquared' in your sortDescriptor.

Depending on the number of times that you update the user's position, the distance between stops and the number of stops this might be an optimal solution.

like image 27
Peter Avatar answered Jan 01 '23 15:01

Peter