核心数据中的位置通过NSFetchedResultsController按距离排序?
我在iOS Core数据库中有一组实体对象,用于描述某个位置的某些内容。 我们调用实体位置。 我已经通过在位置上引用了两个属性来实现这一点,即位置 - 纬度和经度,两者都是双倍。 还有其他元素,比如名字。
我正在使用NSFetchedResultsController将实体绑定到UITableViewController。 我想要做的是将结果按照给定CLLocationCoordinate2D的距离排序。 在一个非常理想的情况下,我可以刷新该列表以重新计算基于新位置的排序。 因此,这种排序取决于两个键和第三个“静态”变量(不同于集合中的项目)。
我想我可以弄清楚如果我使用NSSortDescriptors对任意列表进行排序,该怎么做。 但是,我不控制如何在NSFetchedResultsController中使用排序描述符。
有没有一种方法可以配置我的实体,我的NSFetchedResultsController,我的NSSortDescriptors等来完成这个任务? 我怀疑答案不在于创建花哨的NSSortDescriptor,而是在代表距离的实体中创建瞬态属性,并定期重新计算该属性。 然而,我已经足够新的核心数据,我不知道如何做到这一点(迭代所有实体并重新计算字段)。 我也不确定NSSortDescriptors是否可以处理Transient属性。
(来自评论:)
(基于SQLite的)Core Data存储的获取请求不能使用基于瞬态属性或基于Objective-C的谓词的排序描述符。
如果您不想放弃获取结果控制器的优点(如动态表视图更新,自动分组到段等),则必须预先计算到当前位置的距离并将其存储在(持久)属性中的对象。
或者,您可以获取所有对象并将其排序在内存中。 在这种情况下,您可以使用任意的排序描述符。 但是这不能与提取的结果控制器结合使用,因此必须在受管对象上下文中注册更改并在必要时重新加载表。
我发现了BSFetchedResultsController github项目,它是NSFetchResultsController子类,它执行Martin提出的使用任意排序描述符在内存中排序的NSFetchResultsController子类,此外还会注册对上下文的更改并再次考虑任意排序描述符。 总而言之,这是非常令人印象深刻的壮举 我成功地用它来按距离排序如下:
BSFetchedResultsController* fetchedResultsController = [[BSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
// create a location to compare distance to, e.g. current location
CLLocation* sourceLocation = [[CLLocation alloc] initWithLatitude:55.87595153937809 longitude:-4.2578177698913855];
// compare the distance from both to the source location
fetchedResultsController.postFetchComparator= ^(id a, id b) {
Venue* v1 = (Venue*)a;
Venue* v2 = (Venue*)b;
double d1 = [v1.coreLocation distanceFromLocation:sourceLocation];
double d2 = [v2.coreLocation distanceFromLocation:sourceLocation];
return [@(d1) compare:@(d2)];
};
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
由于它的旧项目没有ARC,所以当你包含这两个文件时,请记住在Target,Build Phases中用Compiler Flags -fno-objc-arc标记.m。 另外请注意开发人员认为代码没有准备好,因此如果使用它,请务必进行适当的测试。
在我上面的代码中,我在Venue托管对象子类上有一个transient属性coreLocation,您可以在这里看到如何实现这一点。 此外,距离计算效率低下,您可能需要缓存对象中的距离,而不是每次比较都重新计算一次。
最后,这个项目看起来是因为创建者Daniel Thorpe的Stackoverflow问题没有得到解决,导致他解决了问题并自己发布了唯一的答案,所以我认为如果你发现他的项目有用,你可以善意地投票他的帖子像我一样。
链接地址: http://www.djcxy.com/p/36147.html上一篇: Locations in Core Data sorted by distance via NSFetchedResultsController?
下一篇: How to use Coredata ordered relationships with NSFetchedResultsController