CoreData - Duplicate existing object

为君一笑 提交于 2020-01-31 06:00:01

问题


Hi would like to duplicate an object from my core data db. Right now I'm using

        movement2 = [NSEntityDescription
                                     insertNewObjectForEntityForName:@"Movement" 
                                     inManagedObjectContext:self.managedObjectContext];

        movement2.name = movement.name;
        movement2.value = movement.value;
        movement2.date = movement.date;
        ... 

and it works. but...

Is there any way to copy all the values of movement to movement2, in one line of code?


回答1:


NSManagedObject, unlike NSObject, provides an API to iterate over its attributes and relationships. Or, rather, it's entity description does. It isn't a one-liner, though.

movement2 = [NSEntityDescription insertNewObjectForEntityForName:@"Movement" 
                                          inManagedObjectContext:self.managedObjectContext];
NSEntityDescription *entity = [movement entity];
for (NSString *propertyName in [entity propertiesByName]) {
    [movement2 setValue:[movement valueForKey:propertyName] forKey:propertyName];
}

See the documentation for more details.

This will be enough to clone most of the objects. If database structure is correct, then copying relationships this way, their inverse ones will be updated as well. So, if your Movement had a relationship with, say, MovementDirection, and MovementDirection has an inverse 1-to-many relation parentMovements, this parentMovements set will have both movement and movement2 inside after you call the code above.




回答2:


There's no method in the API to copy NSManagedObjects, since they don't conform to NSCopying, nor to NSCoding. This makes sense considering that it's often not clear how you would want to copy such an object if it has relationships: should it have relations to the same objects, or copies of them? What about those copies? These are difficult questions whose answers probably depend on the nature of the relationships (to-many or to-one), and hence on the specific use cases of Core Data.

So short answer: I'd do what you're doing in your snippet, or maybe write a method to make a copy. It looks like your NSManagedObjects only have simple attributes and no relationships, so it should be straightforward.




回答3:


I've made a rudimentary duplicate extension for NSManagedObject (based on @coverback's answer). Use with care (though for me it works so far)

Swift 4:

enum CopyBehavior {
    case none, copy, deepcopy
}

extension NSManagedObject {
    func duplicate(only: [String]) -> NSManagedObject {
        return duplicate { only.contains($0) ? .copy : .none }
    }

    func duplicate(except: [String], deep: [String] = []) -> NSManagedObject {
        return duplicate { deep.contains($0) ? .deepcopy : except.contains($0) ? .none : .copy }
    }

    func duplicate(byProperties fun: (String) -> CopyBehavior) -> NSManagedObject {
        let duplicate = NSEntityDescription.insertNewObject(forEntityName: entity.name!, into: managedObjectContext!)

        for propertyName in entity.propertiesByName.keys {
            switch fun(propertyName) {
            case .copy:
                let value = self.value(forKey: propertyName)
                duplicate.setValue(value, forKey: propertyName)
            case .deepcopy:
                let value = self.value(forKey: propertyName)
                if let value = value as? NSSet {
                    let copy = value.map {
                        return ($0 as! NSManagedObject).duplicate(byProperties: fun)
                    }
                    duplicate.setValue(copy, forKey: propertyName)
                }
                else if let value = value as? NSOrderedSet {
                    let copy = value.map {
                        return ($0 as! NSManagedObject).duplicate(byProperties: fun)
                    }
                    duplicate.setValue(NSOrderedSet(array: copy), forKey: propertyName)
                }
                else if let value = value as? NSManagedObject {
                    let copy = value.duplicate(byProperties: fun)
                    duplicate.setValue(copy, forKey: propertyName)
                }
                else {
                    fatalError("Unrecognized deepcopy attribute!")
                }
            case .none:
                break
            }
        }

        return duplicate
    }
}


来源:https://stackoverflow.com/questions/9344064/coredata-duplicate-existing-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!