Marcus S. Zarra telah menginspirasi saya untuk membawa ide rekursif ke versi yang berfungsi. Dalam versi ini Anda tidak perlu mengatur kunci di CoreData dan Anda dapat memotong dan menempelkannya di proyek Anda :-)
// 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
}
Kuncinya di sini adalah meneruskan entitas induk sebagai argumen ke rekursi, sehingga kita dapat memutuskan hubungan mana yang harus kita isi dengan data. Jadi keduanya berfungsi: dataStructureFromManagedObject
dan managedObjectFromStructure
dapat menyandikan dan mendekode objek entitas apa pun dari CoreData ke dalam kamus dan kembali menjadi objek.
NSJSONSerialization
developer.apple.com/library/mac/#documentation/Foundation/… stackoverflow.com/questions/6726899/nsjsonserialization-in-ios5