2011-09-26 24 views
2

我在想如何NSCoder將處理下一次解碼時由多個對象共享和編碼的對象。它會創建對象的兩個副本,還是將解碼一個對象並在解碼它的所有其他對象之間共享?NSCoder和/或NSKeyedUnarchiver如何處理同一對象的多個解碼?

我已經提供了下面這種情況的一個小例子。

實施例:

  1. 應用啓動
  2. 對象A和對象B組對象C作爲其代表
  3. 應用接收結束通知。
  4. 對象A和對象B 編碼本身及其所有的對象(包括它們的代表)
  5. 應用程序關閉和重啓
  6. 對象A和對象B 解碼本身及其所有的對象(包括它們的代表)

對象A和對象B在步驟6之後是否共享相同的解碼對象,還是它們每個都有自己的副本?

回答

6

他們將共享對同一對象的引用(除非您要盡力改變該行爲)。

I.e. NSCoding可以處理完全循環,全向,複雜連接的對象圖(只要所有圖參與者都正確支持NSCoding)。

請注意,編碼委託是非常不典型的。代表通常連接到未歸檔的對象圖之後 anarchival,代表充當您的歸檔模型層(或歸檔視圖層,在IB的情況下 - 對於XIB文件來說故事更加複雜...但是......足夠接近)和其他應用程序。

+0

是的,我通常不會編碼一個代表。我無法在短時間內想到一個更好的例子。我想我可以使用我的實際情況,但我比所需要的輸入更多。無論如何,謝謝! –

+0

不用擔心 - 只是想確認一下。 :) – bbum

0

我不認爲第一個答案是完全正確的。根據Apple的文檔,「序列化只保留對象的值及其在層次結構中的位置,對同一個值對象的多次引用在反序列化時可能導致多個對象」。

因此,不能保證從這些多個NSCoders反序列化時,單個對象序列化將導致單個對象。

如果你的實現是類似於你的例子,那麼你可能沒有考慮事情是否正確。如果您考慮應用程序的邏輯組織結構,那麼多個對象可以共享相同的委託可能是有意義的。但通常我不希望有人使用NSCoder協議來編碼/解碼代表。通常我會希望委託對它作爲委託的對象進行編碼/解碼。

例如,我們來看看NSTableView。也許用戶可以配置如何顯示NSTableView(也許用戶可以調整列大小或選擇顯示哪些列)。這是您可能想要使用NSCoding協議保存和恢復的有用信息。 NSTableView也有代表。代理應該是一個控制器(來自MVC範例),並且永遠不需要使用NSCoding進行編碼/解碼,因爲它是通用代碼,不必維護任何運行時狀態。

所以理想情況下,您使用init方法創建委託/控制器。它意識到需要配置一個NSTableView來查看它上次用戶配置它的方式,因此它使用NSCoding從磁盤中提取舊的表視圖,然後將其顯示給用戶,就像他們上次看到它時一樣。

我認爲MVC範式中的Model層也是如此。同樣,Controller層應該解碼特定於用戶通過使用應用程序完成的模型對象。

這聽起來更像是你試圖從模型或者視圖層實例化控制器層。它沒有任何意義。

+0

公平點,但沒有回答這個問題,這是關於存檔的行爲。可以是對這個問題的評論,或者是一個簡短的記錄,例如bbum的答案。 –

+0

「對同一個**值對象**進行多次引用可能導致反序列化時出現多個對象」。那些對象更好的是-isEqual:和--hash一樣。這應該在文檔中澄清。 – bbum

+0

我的回答是在第一段。 – Carter

3

這是一個很好的問題,我一直都在想自己。所以,我寫了一個小測試程序來試用。四類:ClassA,ClassB,ClassCMyBaseClassClassA,ClassBClassC繼承自MyBaseClass,其符合NSCoding並提供兩個屬性:nameage。除了ClassAClassB還包含對ClassC的實例的引用外,A,B和C類是相同的。 ClassAClassB也覆蓋initwithCoder:encodeWithCoder:來解碼和編碼它們對ClassC實例的引用。這裏是頂級代碼的樣子:

ClassA *a = [[ClassA alloc] initWithName:@"Mr. A" age:11]; 
ClassB *b = [[ClassB alloc] initWithName:@"Mrs. B" age:22]; 
ClassC *c = [[ClassC alloc] initWithName:@"Ms. C" age:33]; 

b.c = c; 
a.c = c; 

NSArray *rootObject = @[a, b, c]; 
NSString *const kFilePath = @"/Users/myname/Documents/testarchive"; 
BOOL result = [NSKeyedArchiver archiveRootObject:rootObject toFile:kFilePath]; 
NSLog(@"result = %@", (result) ? @"YES" : @"NO"); 

NSArray *newRootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:kFilePath]; 
NSLog(@"new root object = %@", newRootObject); 

的對象序列化和反序列化完美。另外,在反序列化之後,a.cb.c指向ClassC的相同實例 - 也就是說,它們的對象指針具有相同的地址。

顯然,內NSKeyedArchiverencodeObject:forKey:,進行測試做,以查看是否正被編碼isEqualTo:物體的先前編碼的對象,並且如果它是,參考被存儲,而不是一個完整的對象。相反必須發生在NSKeyedUnarchiverdecodeObject:forKey:。很酷!

相關問題