2009-09-03 90 views
18

這是一個iPhone應用程序,但我不認爲這真的很重要。我需要使用iPhone的GameKit通過藍牙發送一個自定義對象(由Core Data管理)。通常情況下,我只是使用NSKeyedArchiver將對象打包爲數據對象,然後將其傳送到線上,然後將對象解除封存並完成。當然,我也需要在自定義對象中實現initWithCoder:和encodeWithCoder:方法。我可以編碼NSManagedObject的子類嗎?

我不確定這是否可以使用由Core Data管理的NSManagedObject類來完成。他們會一起玩嗎?我猜想,一旦我將編碼後的託管對象傳送到其他設備並取消編碼,我只是將這個接收到的對象添加到其他設備的上下文中。它是否正確?我錯過了任何步驟?

回答

27

NSManagedObject實例不能存在有意義的NSManagedObjectContext實例外,所以我不會刻意嘗試做直接序列化和反序列化上下文NSManagedObject兩者之間所需要的NSCoding舞蹈(你可以做到這一點,見下文) 。相反,我會創建一個具有適當屬性鍵/值的字典(可以通過instance.entity.attributesByName.allKeys通過託管對象實例的屬性名稱獲得屬性名稱(您可以使用[instance dictionaryWithValuesForKeys:keys]獲取屬性:值對的字典)。我將發送關係信息as NSURL -encoded NSManagedObjectIDs。不要忘記在字典中包含實例managedObjectID(作爲NSURL),以便您可以重新連接任何關係另一端的對象,您必須遞歸創建這些字典您正在編碼的實例的任何關係目標

然後通過網絡發送字典並在另一端重新構建它們作爲新託管中的實例對象上下文(您可以使用setValuesForKeysWithDictionary:)。

您可能會注意到,這正是NSCoder系統會爲你做什麼,除非你將不得不使用classForCoderreplacementObjectForCoder:awakeAfterUsingCoder:與自定義NSDictionary子類來處理所有的NSManageObject至 - NSDictionary映射和簽證一起反之亦然。根據我的經驗,這段代碼比它的價值更麻煩,除非你有一個你試圖序列化的複雜/深層對象圖。對於一個沒有關係的單個實例,只需要轉換爲字典並自己回來確實比較容易。

+0

我有同樣的問題,而且我最終做了巴里所說的 - 它工作得很好。 – jeff7091 2009-11-24 06:15:38

+0

它會好也代替NSDictionary,我只會有一個與我的NSManagedObject相同的模型?那裏我會做映射? – bluezald 2012-06-21 02:45:04

+0

任何人都可以請解釋NSURL編碼NSManagedObjectIDs如何有助於關係?謝謝! – 2012-07-10 16:57:29

2

我建議字典解決方案更簡單的選項。但是,這是我如何解決這個問題。我的模型已經很大並且很健壯,自定義類和單個根級別高於NSManagedObject

所有我需要的是針對單個類調用適當的指定初始化的NSManagedObject[super initWithEntity:insertIntoManagedObjectContext:]。這種方法以及NSEntityDescription中的元數據是設置所有動態訪問器的實現。

- (id)initWithCoder:(NSCoder *)aDecoder { 
    CoreDataStack *cds = [LibraryDiscoverer unarchivingCoreDataStack]; 
    NSEntityDescription *entity = [cds entityDescriptionForName:[[self class] entityName]]; 
    NSManagedObjectContext *moc = [cds managedObjectContext]; 
    self = [super initWithEntity:entity insertIntoManagedObjectContext:moc]; 
    self.lastEditDate = [aDecoder decodeObjectForKey:@"lastEditDate"]; 
    return self; 
} 

CoreDataStack是我對CoreData的一種抽象。 LibraryDiscoverer是獲取核心數據信息的全局訪問鉤子。 entityName是一種定義從類名提供實體名稱的方法;如果遵循命名約定(即類名稱=實體名稱),則可以通用地實施它。

我的類層次結構中的所有其他initWithCoder:方法都是標準NSCoder,注意你不需要編碼關係的兩個方向,CoreData會爲你重新連接它。 (正如往常一樣,包括字典解決方案在內。)

+0

不錯的解決方案。當你有兩堆時你將如何處理這個問題?我目前正在研究通過網絡與應用程序的另一個實例進行通信的應用程序。在我的測試目標中,我有一個測試通信的單元測試。在這種情況下,我需要兩個不同的堆棧。如何結合上面給出的例子來解決這個問題? – 2011-08-12 15:16:57

+0

我實際上創建了一個新的獨特堆棧來進行解除存檔,然後保存上下文(主堆棧監聽並更新),然後刪除導入堆棧。如果你想得到複雜的'unarchivingCoreDataStackForCoder:(NSCoder *)decoder',你可以*保留一個NSCoder映射 - >堆棧。 – bshirley 2011-08-12 16:14:27

相關問題