I have an NSManagedObject class that's persisted in a SQLite database in Core Data. This object has persistent Latitude and Longitude properties. I'm trying to create an NSFetchedRequestController that fetches all of the instances of that class that are within a certain distance from the user. Having done some research, it seems impossible to do this with Core Data, because Core Data only supports bounding-box style queries, not predicates with blocks.
For example, I have a class of Groups with latitude and longitude properties. Given the latitude and longitude (of, say, a user), fetch all groups that are within a 6 mile radius of the given latitude and longitude.
class Group{
var latitude: Float
var longitude: Float
}
I'd like to take advantage of Core Data's R-Tree Indexing to do a fast bounding-box query on the latitudes and longitudes of instances of my class near my user. Then I'd like to filter the results with a more precise predicate, using my own block of code to see which of the instances are within my users current location. Here's the "Bounding box" query.
let request: NSFetchRequest<Group> = Group.fetchRequest()
let (topLeft,bottomRight) = boundingBox(center: center, radius: searchRadius)
let maxLat = topLeft.latitude
let minLon = topLeft.longitude
let minLat = bottomRight.latitude
let maxLon = bottomRight.longitude
let predicate = NSPredicate(format: "(%f < longitude AND longitude < %f) AND (%f < latitude AND latitude < %f)", minLon, maxLon, minLat, maxLat)
request.predicate = predicate
The problem is that I'd like a fetch that looked like this:
let location: CLLocation = /* Initialize a CLLocation */
let predicate = NSPredicate { (obj, _) -> Bool in
let object = obj as! Group
let objLocation = CLLocation(latitude: Double(object.latitude), longitude: Double(object.longitude))
return location.distance(from: objLocation) < 9656 //6 miles in meters
}
NSFetched results controller doesn't allow predicate with block. There's a significant difference between these two fetches. The first gets all groups in a Bounding Box, (the minLat, minLon, maxLat, and maxLat), the latter gets all groups in a Circle of a given radius.
I want to then use an NSFetchedRequestController to display the results in a table, and take advantage of the nice auto-update features. But of course, Core Data only supports bounding-box style queries, not the two-step filter method I need. Is there a proper solution?
I'm open to using other databases, if Core Data simply won't work with this type of use. I took a look at YapDatabase, and it seems more flexible, and includes R-Tree indexing, but I'm concerned that it's not well supported. Realm doesn't support R-Tree Indexing.