CoreData - 复制现有对象

时间:2012-02-18 18:44:05

标签: ios core-data duplicate-data

您想从我的核心数据db复制一个对象。现在我正在使用

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

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

它有效。但...

有没有办法在一行代码中将movement的所有值复制到movement2

3 个答案:

答案 0 :(得分:10)

与NSObject不同,NSManagedObject提供了一个API来迭代其属性和关系。或者,相反,它是实体描述。不过,这不是一个单行。

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

有关详细信息,请参阅the documentation

这足以克隆大多数对象。如果数据库结构正确,那么以这种方式复制关系,它们的反向关系也会更新。因此,如果您的Movement与MovementDirection有关系,并且MovementDirection具有反向1对多关系parentMovements,则此parentMovements集将同时具有movement和{{1在你调用上面的代码后,在里面。

答案 1 :(得分:1)

API中没有方法可以复制NSManagedObjects,因为它们不符合NSCopying,也不符合NSCoding。这是有道理的,因为如果它有关系,你通常不清楚如何复制这样的对象:它应该与相同的对象有关系,还是它们的副本?这些副本怎么样?这些是难题,其答案可能取决于关系的性质(对多或一对),因此取决于核心数据的具体用例。

如此简短的回答:我会在你的片段中做你正在做的事情,或者写一个方法来制作副本。看起来你的NSManagedObject只有简单的属性而没有关系,所以它应该很简单。

答案 2 :(得分:1)

我为NSManagedObject做了一个基本的重复扩展(基于@ coverback的回答)。小心使用(虽然对我来说它迄今为止有效)

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
    }
}