8

NSSortDescriptorCore Data 対多関係を使用する場合、エンティティとの 1 対多関係にあるエンティティParentの数に基づいて、エンティティを使用してフェッチ要求を並べ替えることが非常に難しいというのは、長年の問題です。これは、 と組み合わせると特に便利です。通常、ソート記述子を次のように初期化します。childrenChildNSFetchedResultsController

NSSortDescriptor *sortByNumberOfChildren = [[NSSortDescriptor alloc] initWithKey:@"children.@count" ascending:NO];

例外が発生します'Keypath containing KVC aggregate where there shouldn't be one; failed to handle children.@count

iOS 6.1では、 KVOアクセサー-countOf<Key>を属性として管理対象オブジェクト モデルに整数型として追加することで修正を発見しました。NSManagedObjectすべての魔法は内部で発生しているように見えるため、サブクラスではこの属性に何も実装しませんでした。( https://stackoverflow.com/a/15546371/2042527を参照)。

ただし、これはiOS 6.0では機能しません。NSManagedObjectここで、サブクラスに次のメソッドを追加すると問題が解決することがわかりました。

- (NSUInteger)countOfChildren{
      return [self.children count];
  }

両方を追加しても、両方の SDK の問題は解決されません。それどころか、それは修正を壊します。

iOS 6.0 と iOS 6.1 の間で Core Data または Foundation の変更について言及されていないにもかかわらず、なぜこれが起こっているのか、なぜ両方に違いがあるのか​​ 、誰も手がかりを持っていますか.

4

1 に答える 1

7

「あるべきではない KVC 集合体を含むキーパス。children の処理に失敗しました。@count」ということで、Core Data はこの種のソート記述子をサポートしていないことを伝えたいと考えています。これは、バッキング SQLite ストアがフェッチ リクエストを受信したときに、フェッチ リクエストに記述されていることを実行する SQL を生成する必要があるためです。「children.@count」のケースは、実際には、思ったよりも複雑です。

-countOfChildren を上書きする「修正」は、実際には修正ではありません。これで問題が修正され、すべての親で -countOfChilden が呼び出されると仮定しましょう。初めて self.children にアクセスするとき、Core Data は (少なくとも) 子の主キーを決定する SQL クエリを実行し、NSManagedObjectIDs、NSManagedObjects を作成して結果を返す必要があります。これが機能した場合、非常に悪いパフォーマンスが表示されます。

あなたの問題にはいくつかの解決策があります。

1.子の数を永続的な属性に保存します

親エンティティに属性 (名前: cachedCountOfChildren、タイプ: 整数 64 ビット) を追加するだけです。コントローラー層 (モデル層ではありません) では、子を親に割り当てるたびに cachedCountOfChildren を 1 増やし、親から子を削除するたびに cachedCountOfChildren を減らします。次に、ソート記述子キーで cachedCountOfChildren を使用します。これは素晴らしいパフォーマンスを発揮します。

2. 辞書の結果を使用する

NSFetchRequest の resultType を NSDictionaryResultType に設定します。これにより、-executeFetchRequest:error: が NSManagedObjects の代わりに NSDictionaries を返します。NSDictionaryResultType を持つ NSFetchRequest は、さまざまなことを行うことができます。たとえば、setPropertiesToGroupBy と NSExpression (...) を使用できます。WWDC セッション「Using iCloud with Core Data (2012)」(スライド 122 以降) を参照してください。基本的に、この構造を持つ辞書を含む配列を返すリクエストを作成する方法を示します。

(
 {
  countOfChildren = 1;
  parentName = "hello";
 },
 {
  countOfChildren = 134;
  parentName = "dsdsd";
 },
 {
  countOfChildren = 2;
  parentName = "sdd";
 }
)

ご覧のとおり、ソートされていない結果が返されます。ただし、この配列を countOfChildren で並べ替えると、メモリ内で非常に効率的に実行できます。この場合、Core Data によって生成された SQL も非常に効率的であり、辞書に含める属性を正確に指定できます。したがって、結果はメモリ効率も非常に高くなります。このソリューションには、countOfChildren を追跡する必要がないという利点があります。

状況に応じて、自分に最適なソリューションを決定する必要があります。

于 2013-09-20T16:29:08.607 に答える