1

更新: このスレッドは、コレクション ビューの表現されたオブジェクトが NSManagedObjects である場合の NSCollectionView のバグを特定します。バグは次のようにトリガーされます。

(a) NSArrayController からオブジェクトを削除します。(b) 削除後、NSCollectionView がアニメーションを終了する前に、関連する nsmanagedobjectcontext に対して保存を実行します。

github のこれらのプロジェクトは、この問題を示しています。

https://github.com/artifacts/NSCollectionViewCoreDataBug https://github.com/iracooke/CoreDataCollectionViewCrashing

以下の元の質問

コンテンツ バインディングがコア データ エンティティの NSArrayController の ArrangeObjects にバインドされた NSCollectionView セットアップがあります。コレクション アイテム ビュー (NSCollectionView ビューのプロトタイプ) には、コレクション ビュー アイテムのpresentedObject を介してコア データ エンティティにバインドされたいくつかのコントロールがあります。

ほとんどの場合、これで問題なく動作します。

ArrayController からエンティティを削除しようとすると、objc_exception が発生します。これらのエンティティは、呼び出すだけで削除できます。

[myArrayController removeObject:managedObjectToDelete];

残念ながら、これを行うと、「CoreData は障害を実行できませんでした」というエラーが頻繁に発生します。責任のあるエンティティは、NSArrayController によって管理されているエンティティの 1 つです。

例外がスローされたときにコール スタックを調べると、NSCollectionView が _endOfAnimation メソッドを受け取ったときにクラッシュが発生したことがわかります。これにより、バインドを解除するための他のメソッドが開始されます (ビュー内のコントロールを持つエンティティのプロパティの可能性があります)。

もう 1 つの情報は、私が扱っているエンティティは、モデル内の他のエンティティとは関係がないということです。

次の問題が発生しているように見えます。

  • NSArrayController からオブジェクトを削除すると、それらはコンテキストから削除されます。
  • コンテキストから削除した後、オブジェクトはフォールトに変わります
  • NSCollectionView は、オブジェクトへの参照を保持しています (現在はフォールト)。アニメーションの最後にそれらをクリーンアップしようとします (バインド解除など)。
  • NSCollectionView がオブジェクトへのバインドをクリーンアップしようとすると、コア データがオブジェクトで障害を発生させようとします (用語が正しく理解されていることを願っています)。オブジェクトがまだディスクに保存されていないため、エラーが発生します。

これを防ぐために私が考えることができる唯一の方法は、オブジェクトを削除する前に (保存して) ストアに保持することです。これは機能しますが、もう一度保存する前に1ラウンドの削除が完了したことを確認する必要があるため、ハック的な方法でのみ...そしてアニメーション中にエラーが発生するため..少し遅れて..2回連続して保存すると再度同じエラーが発生します。

これは、Core-Data を使用した NSArrayController を使用して NSCollectionView を設定できないということですか? そうでない場合、私は何を間違っていますか?この問題を回避するより良い方法はありますか?

4

2 に答える 2

2

直接的でありながら退屈な答え: Core Data でサポートされている NSArrayController が NSCollectionView にデータを入力できることを確認できます。コレクション NSView アイテム内のさまざまな GUI オブジェクトが、生成された「Collection View Item」にバインドされ、パスに沿ってさまざまな Core Data オブジェクトを参照します。NSArrayController の要素をプログラムで削除 (および並べ替え) できます (無料のアニメーション付き)。

コレクション ビュー内のバインディングやその他の依存関係が問題を引き起こしている可能性がありますか? または、管理対象オブジェクト コンテキストのスレッド化の問題ですか?

于 2011-06-28T03:17:18.757 に答える
1

対応する ArrayController を指す CollectionItem に (割り当て) プロパティを追加することで、この問題を回避できます。

このプロパティは -[YourNSCollectionViewSubClass newItemWithRepresentedObject:] で設定できます。

すると、各項目で ArrangeObjects を観察できます。変更され、item.representedObject が ArrangeObjects に含まれなくなった場合は、item.representedObject を nil に設定します。私のテスト (10.6.8) では、CoreData がオブジェクトを障害に変える前に、バインディングのクリーンアップがトリガーされます。(私のオブジェクトには関係があり、アイテム ビューにはそれらへのバインディングがあります)。

ところで: この問題は、アニメーション中の保存に限定されません。元に戻す/やり直し/保存の組み合わせでも発生する可能性があります。

アイテム内の観察を開始するのに適した場所を探していましたが、思いついたのは copyWithZone: だけでした。これは避けたかったのです。(-awakeFromNib は最初のアイテムに対してのみ呼び出されます。-view は早すぎます)。

したがって、私は (しぶしぶながら) -newItemWithRepresentedObject: で観察を開始し、アイテムの -dealloc で停止することにしました。

また、アイテム ビュー内のオブジェクトによってトリガーされるコントロールやその他のアクションにも注意する必要があります。すばやくクリックすると、メッセージがオブジェクトの割り当てを解除される可能性があります。私の解決策は、presentedObject を nil に設定するときにコントロールを無効にすることです。YMMV。

ここに私のオブザーバーコードがあります:

    - (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if( object == self.arrayController && [keyPath isEqualToString: @"arrangedObjects"] ) {
        if( NO == [self.arrayController.arrangedObjects containsObject: self.representedObject] ) {
            self.representedObject = nil;

            for(NSView *subview in [self.view subviews]) {
                if( [subview isKindOfClass: [NSControl class]] ) {
                    [(NSControl *)subview setEnabled: NO];
                }
            }
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject: object change:change context:context];
    }
}
于 2011-08-05T03:30:50.620 に答える