7

我在iOS Core Data数据库中有一组实体对象,用于描述某个位置的某些内容。我们调用实体位置。我已经通过在位置上引用了两个属性来实现这一点,即位置 - 纬度和经度,两者都是双倍。还有其他元素,比如名字。核心数据中的位置通过NSFetchedResultsController按距离排序?

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

我想我可以弄清楚如何使用NSSortDescriptors排序任意列表。但是,我不控制如何在NSFetchedResultsController中使用排序描述符。

有没有一种方法可以配置我的实体,我的NSFetchedResultsController,我的NSSortDescriptors等来完成此操作?我怀疑答案不在于创建花哨的NSSortDescriptor,而是在代表距离的实体中创建瞬态属性,并定期重新计算该属性。然而,我已经足够新的核心数据,我不知道如何做到这一点(迭代所有实体并重新计算字段)。我也不确定NSSortDescriptors是否可以处理Transient属性。

+0

不幸的是,获取的结果控制器无法对瞬态属性或计算属性进行排序。请参阅http://stackoverflow.com/questions/13292582/nspredicate-with-function-not-working或http://stackoverflow.com/questions/12027769/nssortdescriptor-sort-by-location了解类似的问题和参考文档。 –

+0

谢谢!我看到了这一点,这就是为什么我认为答案可能在计算我的核心数据实体中的值。让我们从表格中获取瞬态 - 如果它不是一个瞬态场,我将如何定期更新一组实体? –

+0

你真的需要一个提取的结果控制器吗?如果您将对象提取到数组中,则可以在内存中对该数组进行排序,并将其用作表视图的数据源。 –

回答

12

(从评论:)

取指用于基于一个(SQLite的)核心数据存储不能排序使用请求描述符基于瞬态属性或Objective-C的基于谓词。

如果您不希望失去获取结果控制器的优点(如动态表视图更新,自动分组到段等),则必须预先计算到当前位置的距离并将其存储在(持久)属性。

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

0

我发现了BSFetchedResultsController github project这是一个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,所以当你包含两个文件切记要与编译器标志的.M -fno-objc -arc在目标阶段,建立阶段。另外请注意开发人员认为代码没有准备好,因此如果使用它,请务必进行适当的测试。

在我上面的代码中,我在我的Venue托管对象子类上有一个transient属性coreLocation,您可以看到如何实现该here。此外,距离计算效率低下,您可能需要缓存对象中的距离,而不是每次比较都重新计算一次。

最后,这个项目似乎是因为创建者Daniel Thorpe的Stackoverflow问题没有得到答案,导致他解决了问题并发布了自己的唯一答案,所以我认为如果您发现他的项目有用,您可以亲切地致电up-vote his post像我一样。

相关问题