8

iOS Core Dataデータベースに、ある場所で何かを説明する一連のエンティティオブジェクトがあります。エンティティをLocationと呼びましょう。場所を参照する場所に2つの属性(緯度と経度)を設定することでこれを実装しました。どちらも2倍です。名前のような他の要素があります。

NSFetchedResultsControllerを使用して、エンティティをUITableViewControllerにバインドしています。私がやりたいのは、特定のCLLocationCoordinate2Dまでの距離で結果を並べ替えることです。本当に理想的なシナリオでは、そのリストを更新して、新しい場所に基づいて並べ替えを再計算することができます。したがって、この並べ替えは2つのキーと、3番目の「静的」変数(コレクション内のアイテム間で変化しない変数)に依存します。

NSSortDescriptorsを使用して任意のリストを並べ替えていれば、これを行う方法を理解できたと思います。ただし、NSFetchedResultsControllerでソート記述子がどのように使用されるかは制御しません。

これを実現するために、エンティティ、NSFetchedResultsController、NSSortDescriptorsなどを構成する方法はありますか?その答えは、派手なNSSortDescriptorを作成することではなく、私までの距離を表すエンティティに一時的な属性を作成し、その属性を定期的に再計算することにあると思います。ただし、Core Dataは初めてなので、これを行うのに最適な方法がわかりません(すべてのエンティティを繰り返し処理し、フィールドを再計算します)。NSSortDescriptorsが一時的な属性で機能するかどうかもわかりません。

4

2 に答える 2

14

(コメントから:)

(SQLiteベースの)Core Dataストアのフェッチ要求では、一時的な属性またはObjective-Cベースの述語に基づくソート記述子を使用できません。

フェッチされた結果コントローラーの利点(アニメーション化されたテーブルビューの更新、セクションへの自動グループ化など)を失いたくない場合は、現在の場所までの距離を事前に計算し、それを(永続的な)属性に格納する必要があります。あなたのオブジェクトの。

または、すべてのオブジェクトをフェッチして、メモリ内で並べ替えることもできます。その場合、任意のソート記述子を使用できます。ただし、これをフェッチされた結果コントローラーと組み合わせることはできないため、管理対象オブジェクトコンテキストの変更を登録し、必要に応じてテーブルを再ロードする必要があります。

于 2012-12-07T06:22:28.780 に答える
0

NSFetchResultsControllerサブクラスであるBSFetchedResultsControllergithubプロジェクトを発見しました。これは、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がありません。したがって、2つのファイルを含める場合は、ターゲットのビルドフェーズでコンパイラフラグ-fno-objc-arcを使用して.mをマークすることを忘れないでください。また、開発者はコードが本番環境に対応していないと考えていることに注意してください。使用する場合は、適切なテストを必ず行ってください。

上記のコードでは、Venue管理対象オブジェクトサブクラスに一時プロパティcoreLocationがあります。これを実現する方法は、ここで確認できます。また、距離の計算は非効率的です。比較のたびに距離を再計算するのではなく、オブジェクトに距離をキャッシュすることをお勧めします。

最後に、このプロジェクトは、作成者のDaniel ThorpeのStackoverflowの質問に回答がなく、問題を解決して自分で唯一の回答を投稿したことが原因のようです。彼のプロジェクトが役に立ったら、彼の投稿に賛成票を投じてください。私がしたように。

于 2015-04-23T00:04:05.393 に答える