Reputation: 21
I'm trying to display some Spots in a UITableView
with NSFetchedResultsController
associated to the Database.
The problem is that I need to filter the results by a distance (radio) from a specific Location. I read that it is not possible to a NSPredicate
that calculate distance, so I'm getting all the Spots in an area around the Location with a simple comparation with the coordinates. That gives me a Square around the Location. Then, I want to iterate the results of the fetchedObjects
and remove the ones that are not in the Zone.
- (NSFetchedResultsController *)newFetchedResultsControllerWithSearch:(NSString *)searchString{
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:sectionName
cacheName:@"Stores"];
aFetchedResultsController.delegate = self;
NSError *error = nil;
if (![aFetchedResultsController performFetch:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
// ITERATE FETCHED OBJECTS TO FILTER BY RADIO
int n = [aFetchedResultsController.fetchedObjects count];
NSLog(@"Square result count: %i",n);
self.footerLabel.text = [NSString stringWithFormat:NSLocalizedString(@"%i Spots", @"%i Spots"),n];
return aFetchedResultsController;
How can I remove object from the aFetchedResultsController
.fetchedObjects before returning it?? Will it alterate the methods used in UITableView
like [fetchedResultsController objectAtIndexPath:indexPath]
?
Thanks
Upvotes: 1
Views: 3748
Reputation: 7200
Geohash.
So its a string that has the location where you can do a 'like' SQL query and get results around an area.
From wikipedia " Geohash is a geocoding system invented by Gustavo Niemeyer and placed into the public domain. It is a hierarchical spatial data structure which subdivides space into buckets of grid shape, which is one of the many applications of what is known as a Z-order curve, and generally space-filling curves.
Geohashes offer properties like arbitrary precision and the possibility of gradually removing characters from the end of the code to reduce its size (and gradually lose precision).
As a consequence of the gradual precision degradation, nearby places will often (but not always) present similar prefixes. The longer a shared prefix is, the closer the two places are."
Upvotes: 0
Reputation: 570
Use you fetchedResultController
NSError *error;
if (filter) { // check if you need to filter
// set predicate to self.fetchedResultController.fetchRequest
self.fetchedResultController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"your filter params"]];
}else{
// if you dont need to filter and you need to show all objects set predicate to nil
self.fetchedResultController.fetchRequest.predicate = nil;
}
// and perform fetch!
if (![self.fetchedResultController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
don't forget update UI after perFormFetch
Upvotes: 0
Reputation: 540055
You cannot modify the result set of a fetched results controller (FRC). You can filter the results, but that does not help if the FRC is used as data source for a table view.
Possible solutions:
Pre-calculate the distances to the current locations and store the distances as a persistent attribute in the database. Then you can use a filter on the distance directly in the fetch request of the FRC. The big disadvantage of course is that you have to re-calculate the distances when the current location changes.
Don't use a fetched results controller. Perform a fetch request and filter the results of the fetch request according to the radius into an array, and use this array as data source for the table view. The big disadvantage here is that you lose the automatic update features of the FRC. You would have to reload the table view each time the radius or other search parameters are changed.
I know that both solutions are not satisfying, but I don't think there is a method to combine a fetched results controller with a function based filter.
Upvotes: 2
Reputation: 80271
The proper method to do this is to set a new fetch request which includes your predicate. The fetched results controller's fetchRequest
is read only, so you have to put the logic into the the lazy initialization of the fetched results controller itself.
if (searchIsActive) {
fetchRequest.predicate =
[NSPredicate predicateWithFormat:
@"(%K < %@ && %K > %@) && (%K < %@ && %K > %@)",
@"lat", @(locationLat + limit), @"lat", @(locationLat - limit),
@"lon", @(locationLon + limit), @"lon", @(locationLon - limit)];
}
else { fetchRequest.predicate = nil; }
Then, to update the table, just set the controller to nil and reload
self.fetchedResultsController = nil;
[self.tableView reloadData];
Upvotes: 0
Reputation: 3152
Use NSPredicate to search/filter trough the array.
Example:
NSString *modelName = @"honda";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"model == %@", modelName];
NSArray *filteredArray = [results filteredArrayUsingPredicate:predicate];
Upvotes: -1