Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoreData - Duplicate existing object

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?

like image 250
Abramodj Avatar asked Oct 19 '25 09:10

Abramodj


2 Answers

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.

like image 62
coverback Avatar answered Oct 21 '25 23:10

coverback


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
    }
}
like image 21
Ivorius Avatar answered Oct 21 '25 23:10

Ivorius



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!