我希望你能原谅这个问题看似广泛的性质,但它变得非常具体。
我正在构建一个基于文档的 Cocoa 应用程序,它与大多数其他应用程序一样工作,只是我将 SQLCipher 用于我的数据存储(SQLite 的一种变体),因为您无法在 Core Data 中设置自己的持久数据存储,并且我也真的需要使用这个。
在我的文档子类中,我有一个NSMutableArray
名为categories
. 在文档 nib 中,我NSArrayController
绑定了 to categories
,并且NSCollectionView
绑定了数组控制器。
数组中的每个模型对象(每个都是 a Category
)都绑定到底层数据存储中的记录,所以当 Category 的某些属性发生变化时,我想调用[category save]
,当 Category 添加到集合中时,我想再次调用 ,[category save]
最后,当一个类别被删除时,[category destroy]
。
我已经建立了一个部分解决方案,但它在移除要求上分崩离析,在我看来,关于它的一切似乎都在吠叫错误的树。无论如何,这就是发生的事情:
一旦文档和笔尖都加载完毕,我开始观察类别属性,并为其分配一些数据:
[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]
从我的观察者那里调用。
一个人应该如何正确地与 NSArrayController 集成以保持对数据模型 pre-Core Data 的更改?如何解决这里的删除问题(或者这完全是错误的方法?)
提前感谢您的任何建议!