8

我的 iOS Core Data 数据库中有一组实体对象,用于描述某个位置的某些内容。让我们称实体位置。我通过在 Location 上有两个引用位置的属性来实现这一点 - 纬度和经度,都是双精度的。还有其他元素,例如名称。

我正在使用 NSFetchedResultsController 将实体绑定到 UITableViewController。我想做的是让结果按到给定 CLLocationCoordinate2D 的距离排序。在一个非常理想的情况下,我可以刷新该列表以根据新位置重新计算排序。因此,这种排序将取决于两个键和第三个“静态”变量(一个不会在集合中的项目之间变化的变量)。

如果我使用 NSSortDescriptors 对任意列表进行排序,我想我可以弄清楚如何做到这一点。但是,我不控制排序描述符在 NSFetchedResultsController 中的使用方式。

有没有办法可以配置我的实体、我的 NSFetchedResultsController、我的 NSSortDescriptors 等来完成这个?我怀疑答案不在于创建一个花哨的 NSSortDescriptor,而是在实体中创建一个表示与我的距离的瞬态属性,并定期重新计算该属性。但是,我对 Core Data 还很陌生,所以我不确定如何最好地做到这一点(遍历所有实体并重新计算一个字段)。我也不确定 NSSortDescriptors 是否适用于瞬态属性。

4

2 回答 2

14

(来自评论:)

对(基于 SQLite)Core Data 存储的获取请求不能使用基于瞬态属性或基于 Objective-C 谓词的排序描述符。

如果您不想失去获取结果控制器的优势(如动画表格视图更新、自动分组到部分等),您必须预先计算到当前位置的距离并将其存储在(持久)属性中你的对象。

或者,您可以获取所有对象并在内存中对它们进行排序。在这种情况下,您可以使用任意排序描述符。但这不能与获取的结果控制器结合使用,因此您必须注册托管对象上下文中的更改并在必要时重新加载表。

于 2012-12-07T06:22:28.780 回答
0

我发现了BSFetchedResultsController github 项目,它是一个 NSFetchResultsController 子类,它执行 Martin 建议的操作,它使用任意排序描述符在内存中排序,此外,它还注册上下文更改并再次计算任何索引更改,同时考虑到任意排序描述符. 总而言之,这是一个非常令人印象深刻的壮举!我成功地使用它按距离排序,如下所示:

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,因此当您包含这两个文件时,请记住在目标、构建阶段中使用编译器标志 -fno-objc-arc 标记 .m。另请注意,开发人员认为代码尚未准备好生产,因此如果使用它,请务必进行充分的测试。

在我上面的代码中,我的 Venue 托管对象子类上有一个瞬态属性 coreLocation,您可以在此处查看如何实现它。此外,距离计算效率低下,您可能希望将距离缓存在对象中,而不是在每次比较时重新计算它。

最后,这个项目似乎是因为创建者 Daniel Thorpe 的 Stackoverflow 问题没有得到解答,导致他自己解决了问题并发布了唯一的答案,所以我认为如果你觉得他的项目有用,你可以给他的帖子投票就像我一样。

于 2015-04-23T00:04:05.393 回答