Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RealmSwift: Detach an object from Realm, including its properties of List type

Tags:

ios

swift

realm

I want to create a duplicate of a persisted object such that the new instance has all the same values but is not attached to Realm. Using Object(value: persistedInstance) works great for classes whose properties are all strings, dates, numbers, etc. However, when duplicating an instance of a class with List type properties, the duplicate's List and the List's elements continue to reference the persisted records. How can I create a duplicate that's fully detached from Realm, including any Lists and elements in those Lists?

like image 910
jhc Avatar asked May 10 '16 13:05

jhc


2 Answers

You can make a deep copy of your object via the following extension functions:

    import UIKit
    import Realm
    import RealmSwift
    
    protocol RealmListDetachable {

    func detached() -> Self
}

extension List: RealmListDetachable where Element: Object {

    func detached() -> List<Element> {
        let detached = self.detached
        let result = List<Element>()
        result.append(objectsIn: detached)
        return result
    }

}

@objc extension Object {

    public func detached() -> Self {
        let detached = type(of: self).init()
        for property in objectSchema.properties {
            guard
                property != objectSchema.primaryKeyProperty,
                let value = value(forKey: property.name)
            else { continue }
            if let detachable = value as? Object {
                detached.setValue(detachable.detached(), forKey: property.name)
            } else if let list = value as? RealmListDetachable {
                detached.setValue(list.detached(), forKey: property.name)
            } else {
                detached.setValue(value, forKey: property.name)
            }
        }
        return detached
    }
}

extension Sequence where Iterator.Element: Object {

    public var detached: [Element] {
        return self.map({ $0.detached() })
    }

}

Use

/// in collections
let data = realm.objects(AbcDfg.self).detached

/// single object
data.first?.detached()
like image 117
Carlos Chaguendo Avatar answered Oct 22 '22 08:10

Carlos Chaguendo


This is not yet supported natively by Realm, but a requested feature tracked by issue #3381.

For now, you would need to implement your own deep copy constructor. A common strategy is to do that on every model and call the deep copy constructors of related objects. You need to pay attention though that you don't run into cycles.

like image 9
marius Avatar answered Oct 22 '22 07:10

marius