0

この質問の一見広範に見える性質をご容赦いただければ幸いですが、かなり具体的になります。

Core Data に独自の永続データ ストアを設定できないため、データ ストア (SQLite の変形) に SQLCipher を使用していることを除いて、他のほとんどのアプリケーションと同じように機能するドキュメント ベースの Cocoa アプリケーションを構築しています。また、私は本当にこれを使用する必要があります。

ドキュメント サブクラスには、NSMutableArrayという名前のプロパティがありますcategories。ドキュメント nib では、へのバインドがあり、配列コントローラへのバインドがありますNSArrayControllercategoriesNSCollectionView

配列内の各モデル オブジェクト (それぞれがCategory) は、基になるデータ ストア内のレコードにバインドされているため、カテゴリの一部のプロパティが変更されたときに を呼び出し[category save]、カテゴリがセットに追加されたときに、再度 を呼び出し、[category save]最後に、カテゴリが削除されたときに を呼び出します[category destroy]

私は部分的な解決策を配線しましたが、削除の要件でバラバラになり、それに関するすべてが間違ったツリーを吠えているように思えます。とにかく、ここで何が起こっているのですか:

ドキュメントと nib がすべて読み込まれたら、categories プロパティの観察を開始し、いくつかのデータを割り当てます。

    [self addObserver:self 
           forKeyPath:@"categories" 
              options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) 
              context:MyCategoriesContext];
    self.categories = [Category getCategories];

ドキュメントが応答してデータストアを更新できるように、変更が通知されるような方法で監視メソッドを実装しました。

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context 
{
    NSNumber *changeKind = (NSNumber *)[change objectForKey:@"NSKeyValueChangeKind"];
    if (context == MyCategoriesContext) 
    {
        switch ([changeKind intValue]) 
        {
            case NSKeyValueChangeInsertion: 
            {
                Category *c = (Category *)[change objectForKey:NSKeyValueChangeNewKey];
                NSLog(@"saving new category: %@", c);
                [c save];
                break;
            }
            case NSKeyValueChangeRemoval:
            {
                Category *c = (Category *)[change objectForKey:NSKeyValueChangeOldKey];
                NSLog(@"deleting removed category: %@", c);
                [c destroy];
                break;
            }
            case NSKeyValueChangeReplacement:
            {
              // not a scenario we're interested in right now...
                NSLog(@"category replaced with: %@", (Category *)[change objectForKey:NSKeyValueChangeNewKey]);
                break;
            }
            default: // gets hit when categories is set directly to a new array
            {
                NSLog(@"categories changed, observing each");
                NSMutableArray *categories = (NSMutableArray *)[object valueForKey:keyPath];
                NSIndexSet *allIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [categories count])];
                [self observeCategoriesAtIndexes:allIndexes];
                break;
            }
        }
    } 
    else if (context == MyCategoryContext) 
  { 
            NSLog(@"saving category for change to %@", keyPath);
            [(Category *)object save];
  }
    else 
    {
        // pass it on to NSObject/super since we're not interested
        NSLog(@"ignoring change to %@:@%@", object, keyPath);
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

そのリストからわかるように (そして既にお気づきかもしれませんが)、categoriesプロパティを観察するだけでは十分ではありません。個々のカテゴリを観察して、属性 (名前など) が変更されたときにドキュメントに通知されるようにする必要があります。その変更をすぐに保存できること:

- (void)observeCategoriesAtIndexes:(NSIndexSet *)indexes {
        [categories addObserver:self 
             toObjectsAtIndexes:indexes 
                     forKeyPath:@"dirty"
                        options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) 
                        context:MyCategoryContext];
}

これは私には大したことのないように見えます。私はここで Cocoa に反対しているのではないかと思いますが、ほとんどの場合はうまくいきます。

除去以外。インターフェイスにボタンを追加し、それをアレイ コントローラのremove:アクションに割り当てるとcategories、ドキュメントのプロパティからカテゴリが適切に削除されます。

そうすることで、カテゴリがまだ監視されている間に割り当てが解除されます。

2010-09-03 13:51:14.289 MyApp[7207:a0f] An instance 0x52db80 of class Category was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x52e100> (
<NSKeyValueObservance 0x2f1a480: Observer: 0x2f0fa00, Key path: dirty, Options: <New: YES, Old: YES, Prior: NO> Context: 0x1a67b4, Property: 0x2f1a3d0>
...
)

[category destroy]さらに、通知を受ける前にオブジェクトの割り当てが解除されたため、オブザーバーから呼び出す機会がありません。

Core Data より前のデータ モデルへの変更を保持するために、NSArrayController と適切に統合するにはどうすればよいでしょうか? ここで削除の問題をどのように回避しますか (または、これは完全に間違ったアプローチですか?)

アドバイスをよろしくお願いします!

4

2 に答える 2

2

いくつかの初期のハッキングに基づいて、NSArrayController をサブクラス化することがここに行く方法であるように思われます。その API でさまざまな insertObject(s) および removeObject(s) メソッドをオーバーライドすると、データ モデルをいじるためにこのロジックを追加するのに最適な場所が得られます。

そしてそこから、コンテンツ配列内の個々のアイテムの変更などを監視し始め、それらを破棄/割り当て解除する前に監視を停止し、親クラスに残りを処理させることもできます。

このソリューションのおかげで、Bill Garrisonは cocoa-unbound リストでそれを提案しました。

于 2010-09-07T20:04:27.550 に答える
1

カテゴリ リストの変更を観察し、リストが変更されたら、mutableCopy を使用してカテゴリの配列をセカンダリ NSArray の「既知のカテゴリ」に格納します。次にリストが変更されたときに、その「既知の」リストを新しいリストと比較します。欠落しているカテゴリ、新しいカテゴリなどがわかります。削除されたカテゴリごとに、監視を停止して解放します。

次に、カテゴリの「既知の」リストの新しい変更可能なコピーを取得し、次の呼び出しに備えます。

カテゴリを保持する追加の配列があるため、準備が整うまでは解放されません。

于 2010-09-07T15:26:41.247 に答える