我希望你能原諒這個問題的表面上寬泛的性質,但它很具體。如何在沒有核心數據或NSKeyedArchiver的情況下堅持由NSArrayController管理的數據?
我建立一個基於文檔的Cocoa應用程序的工作方式類似於其他大多數人不同的是,我使用SQLCipher我的數據存儲(SQLite的一個變體),因爲你不會設置自己的持久數據存儲在覈心數據中,而且我真的需要使用這個。
在我的文檔子類中,我有一個名爲categories
的NSMutableArray
屬性。在文檔筆尖中,我有一個NSArrayController
綁定到categories
,我有一個NSCollectionView
綁定到陣列控制器。
數組中的每個模型對象(每個都是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];
}
這在我看來就像一個大的組裝機,我懷疑我的工作對可可在這裏,但在大多數情況下它的工作原理。
不包括刪除。在界面中添加一個按鈕並將其分配給陣列控制器的動作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正確集成以將更改持久化到數據模型前核心數據?如何解決這裏的移除問題(或者這是完全錯誤的方法?)
在此先感謝您的任何建議!
您對核心數據存儲類型的假設不正確。您可以創建自定義商店類型。您只需創建一個子類並實現所需的方法(請參閱文檔)以在託管對象和持久性機制(SQLCipher)之間進行轉換。 – 2010-09-06 22:30:10
你是錯誤的,你只能核心數據的* atomic *數據存儲,沒有發佈的API來創建你自己的持久*核心數據存儲。 「重要的是要注意原子商店API不支持與客戶端 - 服務器關係數據庫或類似的基於SQL的商店的集成。」 – 2010-09-07 13:48:05
供參考的鏈接:http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/AtomicStore_Concepts/Articles/asFundamentals.html – 2010-09-07 13:48:21