Marcus S. Zarra激励我将递归理念带入工作版本 . 在此版本中,您无需在CoreData中设置密钥,您可以将其剪切并粘贴到项目中:-)
// MARK: - encoding and decoding CoreData entity to dictionary
func dataStructureFromManagedObject( managedObject:NSManagedObject?, parentEntity: NSEntityDescription? = nil) -> NSMutableDictionary {
if (managedObject != nil) {
var attributesByName: NSDictionary = managedObject!.entity.attributesByName
var relationshipsByName: NSDictionary = managedObject!.entity.relationshipsByName
var valuesImmutableDictionary: NSDictionary = managedObject!.dictionaryWithValuesForKeys( attributesByName.allKeys)
var valuesDictionary: NSMutableDictionary = valuesImmutableDictionary.mutableCopy() as NSMutableDictionary
valuesDictionary.setObject( managedObject!.entity.name!, forKey: "ManagedObjectName")
for relationshipNameObject in relationshipsByName.allKeys {
var relationshipName: NSString = relationshipNameObject as NSString
var relationshipDescription: NSRelationshipDescription? = relationshipsByName.objectForKey( relationshipName) as? NSRelationshipDescription
if !relationshipDescription!.toMany {
// ono to one
if parentEntity == nil || (relationshipDescription! as NSRelationshipDescription).destinationEntity != parentEntity! {
// no parent or relationship is "downward" -> object for relationship must be added
var relationshipObject: NSManagedObject? = managedObject!.valueForKey( relationshipName) as? NSManagedObject
var relationshipObjectDictionary: NSMutableDictionary = self.dataStructureFromManagedObject( relationshipObject, parentEntity: managedObject?.entity)
valuesDictionary.setObject( relationshipObjectDictionary, forKey: relationshipName)
} else {
// relationship is "upward" -> nothing to do
}
} else {
// one to many -> all objects must be added
var relationshipObjects: NSSet = managedObject!.mutableSetValueForKey( relationshipName)
var relationshipArray:NSMutableArray = []
for relationshipObjectRaw in relationshipObjects {
var relationshipObject:NSManagedObject? = relationshipObjectRaw as? NSManagedObject
if relationshipObject != nil && !relationshipObject!.entity.isKindOfEntity( managedObject!.entity) {
relationshipArray.addObject(self.dataStructureFromManagedObject( relationshipObject, parentEntity: managedObject?.entity))
}
}
valuesDictionary.setObject( relationshipArray, forKey: relationshipName)
}
}
return valuesDictionary
} else {
return NSMutableDictionary()
}
}
func managedObjectFromStructure( structureDictionary: NSDictionary, moc: NSManagedObjectContext, parentObject: NSManagedObject? = nil) -> NSManagedObject {
if structureDictionary.count > 0 {
var objectName:NSString = structureDictionary.objectForKey( "ManagedObjectName") as NSString
var managedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName( objectName, inManagedObjectContext: moc) as NSManagedObject
var relationshipsByName: NSDictionary = managedObject.entity.relationshipsByName
var realObjectStructure:NSMutableDictionary = structureDictionary.mutableCopy() as NSMutableDictionary
realObjectStructure.removeObjectForKey( "ManagedObjectName")
for key in realObjectStructure.allKeys {
// search for "ManagedObjectName" relationship entrys and delete them before filling the managedObject from this structure
for relationshipName in relationshipsByName.allKeys {
if relationshipName as NSString == key as NSString {
realObjectStructure.removeObjectForKey( key)
}
}
}
managedObject.setValuesForKeysWithDictionary( realObjectStructure)
// the main object with attributes is created. Now care about the relationships
for relationshipName in managedObject.entity.relationshipsByName.keys {
var description:NSRelationshipDescription = relationshipsByName.objectForKey( relationshipName) as NSRelationshipDescription
if !description.toMany {
// to one relationship
if parentObject == nil || description.destinationEntity != parentObject!.entity {
// no parent or relationship is "downward" -> recurse structure to add
var childStructureDictionary:NSDictionary = structureDictionary.objectForKey( relationshipName) as NSDictionary
if childStructureDictionary.count > 0 {
// dictionary not empty -> object must be created and added
var childObject:NSManagedObject? = self.managedObjectFromStructure( childStructureDictionary, moc: moc, parentObject: managedObject)
// validateForUpdate
var error:NSError?
if !managedObject.validateForUpdate( &error) {
println("Error: Object not in valid state for update!!! -> \(error)")
} else {
managedObject.setValue( childObject, forKey: relationshipName as NSString)
}
} else {
// relationship is "upward" -> nothing to do
}
}
} else {
// to many relationship
var relationshipSet:NSMutableSet = managedObject.mutableSetValueForKey( relationshipName as NSString)
var relationshipArray:NSArray = structureDictionary.objectForKey( relationshipName as NSString) as NSArray
for childStructureDictionary in relationshipArray {
if childStructureDictionary.count > 0 {
// dictionary not empty -> object must be created and added
var childObject:NSManagedObject = self.managedObjectFromStructure( childStructureDictionary as NSDictionary, moc: moc, parentObject: managedObject)
// validateForUpdate
var error:NSError?
if !managedObject.validateForUpdate( &error) {
println( "Error: Object not in valid state for update!!! -> \(error)")
} else {
relationshipSet.addObject( childObject)
}
} else {
// no object was behind the relationship -> nothing to do
}
}
// save set
managedObject.setValue( relationshipSet, forKey: relationshipName as NSString)
}
}
// final check validateForUpdate
var error:NSError?
if !managedObject.validateForUpdate( &error) {
println( "Error: Object not in valid state for update although all previous check are passed!!! -> \(error)")
}
return managedObject
} else {
println( "Error: structure for object was empty. this should not happen at this point")
var objectName:NSString = structureDictionary.objectForKey( "ManagedObjectName") as NSString
var managedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName( objectName, inManagedObjectContext: moc) as NSManagedObject
return managedObject
}
}
func dataStructuresFromManagedObjects( managedObjects: NSArray) -> NSArray {
var dataArray:NSMutableArray = []
for managedObject in managedObjects {
dataArray.addObject( self.dataStructureFromManagedObject(managedObject as? NSManagedObject))
}
return dataArray
}
8 回答
首先,选择一个JSON库来使用,我个人喜欢TouchJSON,但其他几个也很不错 . 复杂的部分虽然不是很难,但是要将您的托管对象转换为适合转换的结构 . 我写得这么快,所以它可能有一两个错误:)
你调用的方法是:
实施如下:
现在这是递归的,所以如果你不小心的话,你可以轻松地翻译整个持久性商店 . 观察您的关系并确保它们仅“关闭”对象树,以便您只获取要翻译的对象 .
我只是想指出一个小错字,导致代码崩溃,希望这会节省你几分钟 .
NSMutableArray *dataArray = [[NSArray alloc] init]; // This should be NSMutableArray
真的应该
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
就这些 .
谢谢
Synchronizing Core Data with Rails是一个详细的演示文稿,其中包含用于将核心数据对象序列化/反序列化为JSON的示例代码(跳至核心数据部分的幻灯片55) . 他的示例代码假设一个没有关系的相当简单的模型,但我认为它很容易扩展 .
该演示文稿还详细介绍了如何使您的Core Data模型与基于REST的Web应用程序保持同步,并指向一些有用的库,包括ObjectiveResource和ASIHTTPRequest . 不确定's what you'是否正在尝试这样做,但即使是核心数据代码也值得一看 .
如果您的托管对象中有
NSDate
,如上面其中一条评论中所述,您在序列化包含NSDate
的对象时会遇到问题 . 一个简单的解决方法是使用objective-c类别将JSONDataRepresentation
方法添加到NSDate
.将这两个文件添加到项目中:
NSdate.h:
NSDate.m:
有一个lib为您执行JSON同步:https://github.com/sixdegrees/lidenbrock
我发现这篇文章非常有效 .
http://touchalicious.com/blog/2009/10/25/turn-core-data-models-into-json.html
由于这是递归的,因此多对多关系将继续循环 . 为了避免这种情况,我在核心数据模型中的关系的用户信息字典中添加了一个“isExportable”键 . 然后,您可以检查此密钥,并选择不在没有它的情况下循环关系 .
只是想id发布这个问题的快速更新 . 我按照Marcus和Brandon的回答,为JSON导出提出了这个问题(它仍然使用TouchJSON):
我无法让导入工作,也许这与我使用魔法记录的事实有关,我不确定,所以我只是循环传入传入的JSON流并手动创建对象...
Marcus S. Zarra激励我将递归理念带入工作版本 . 在此版本中,您无需在CoreData中设置密钥,您可以将其剪切并粘贴到项目中:-)
这里的关键是将父实体作为参数传递给递归,因此我们可以决定用数据填充哪个关系 . 因此,这两个函数:
dataStructureFromManagedObject
和managedObjectFromStructure
可以将CoreData中的任何实体对象编码并解码为字典并返回到对象中 .