0

我希望你能原諒這個問題的表面上寬泛的性質,但它很具體。如何在沒有核心數據或NSKeyedArchiver的情況下堅持由NSArrayController管理的數據?

我建立一個基於文檔的Cocoa應用程序的工作方式類似於其他大多數人不同的是,我使用SQLCipher我的數據存儲(SQLite的一個變體),因爲你不會設置自己的持久數據存儲在覈心數據中,而且我真的需要使用這個。

在我的文檔子類中,我有一個名爲categoriesNSMutableArray屬性。在文檔筆尖中,我有一個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正確集成以將更改持久化到數據模型前核心數據?如何解決這裏的移除問題(或者這是完全錯誤的方法?)

在此先感謝您的任何建議!

+0

您對核心數據存儲類型的假設不正確。您可以創建自定義商店類型。您只需創建一個子類並實現所需的方法(請參閱文檔)以在託管對象和持久性機制(SQLCipher)之間進行轉換。 – 2010-09-06 22:30:10

+0

你是錯誤的,你只能核心數據的* atomic *數據存儲,沒有發佈的API來創建你自己的持久*核心數據存儲。 「重要的是要注意原子商店API不支持與客戶端 - 服務器關係數據庫或類似的基於SQL的商店的集成。」 – 2010-09-07 13:48:05

+0

供參考的鏈接:http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/AtomicStore_Concepts/Articles/asFundamentals.html – 2010-09-07 13:48:21

回答

1

我將觀察到的改變的類別列表,並且當所述列表的改變,存儲類別的陣列遠在二次NSArray中,使用mutableCopy「已知類別」,。下次更改列表時,將「已知」列表與新列表進行比較;你可以知道哪些類別丟失,哪些是新的,等等。對於每個被刪除的類別,停止觀察並釋放它。

然後取可變的新副本類別的「已知」列表中,準備下一次呼叫。

由於您有一個額外的陣列來保存這些類別,因此在您準備好之前不會發布它們。

+0

不錯的解決方法! – 2010-09-07 19:58:51

+0

我發現,在一箇舊的蘋果樣品,所以它有一定程度的祝福。 – 2010-09-08 00:23:44

+0

在這裏給@格拉漢姆信貸。不太清楚mutableCopy方法,但我認爲擁有NSMutableArray *類別的對象最終應該觀察對類別本身的修改,以便進行持久化,而不是通過繼承NSArrayController來處理它。所以這在我更成熟的觀點中絕對是最正確的答案! – 2014-03-07 21:28:00

2

這似乎基於一些初步的黑客攻擊,即子類NSArrayController的是去這裏的路。覆蓋該API中的各種insertObject(s)和removeObject(s)方法爲我提供了一個完美的地方,可以在此邏輯中添加數據模型。

從那裏我也可以開始觀察單個項目的內容陣列的變化等,破壞/重新分配它們,等等之前停止觀察,並讓父類處理其餘部分。

感謝這個解決方案是由比爾駐軍誰suggested it可可 - 綁定列表。

相關問題