RealmSwift:从Realm中分离对象,包括List类型的属性

时间:2016-05-10 13:46:12

标签: ios swift realm

我想创建一个持久化对象的副本,以便新实例具有所有相同的值,但不会附加到Realm。使用Object(value: persistedInstance)对于属性都是字符串,日期,数字等的类非常有用。但是,当复制具有List类型属性的类的实例时,复制的列表和列表会被复制。元素继续引用持久化记录。如何创建与Realm完全分离的副本,包括这些列表中的任何列表和元素?

5 个答案:

答案 0 :(得分:6)

Realm本身尚不支持,但requested feature tracked by issue #3381

目前,您需要实现自己的深层复制构造函数。一个常见的策略是在每个模型上执行此操作并调用相关对象的深层复制构造函数。你需要注意,虽然你不会遇到周期。

答案 1 :(得分:5)

您可以通过以下扩展功能制作对象的深层副本:

import UIKit
import Realm
import RealmSwift

protocol RealmListDetachable {

    func detached() -> Self
}

extension List: RealmListDetachable {

    func detached() -> List<T> {
        let detached = self.detached
        var result = List<T>()
        result.append(contentsOf: detached)
        return result
    }

}

public extension Object {

    public func detached() -> Self {
        let detached = type(of: self).init()
        for property in objectSchema.properties {
            guard 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
    }
}


public extension Sequence where Iterator.Element: Object {

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

}

使用

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

/// single object
data.first?.detached()

答案 2 :(得分:3)

我们使用ObjectMapper通过转换为JSON来创建对象的深层副本,然后将该JSON转换回同一个对象,除了它与Realm无关。

麦克

答案 3 :(得分:0)

正如在#3381所跟踪的问题中所提到的那样,目前的解决方案是从Realm对象创建分离副本的实现。 在以下位置有一个更好版本的可分离对象实现 https://github.com/realm/realm-cocoa/issues/5433#issuecomment-415066361

如果链接不起作用,则Alarson93的代码为:

protocol DetachableObject: AnyObject {
    func detached() -> Self
}

extension Object: DetachableObject {

    func detached() -> Self {
        let detached = type(of: self).init()
        for property in objectSchema.properties {
            guard let value = value(forKey: property.name) else { continue }

            if property.isArray == true {
                //Realm List property support
                let detachable = value as? DetachableObject
                detached.setValue(detachable?.detached(), forKey: property.name)
            } else if property.type == .object {
                //Realm Object property support
                let detachable = value as? DetachableObject
                detached.setValue(detachable?.detached(), forKey: property.name)
            } else {
                detached.setValue(value, forKey: property.name)
            }
        }
        return detached
    }
}

extension List: DetachableObject {
    func detached() -> List<Element> {
        let result = List<Element>()

        forEach {
            if let detachable = $0 as? DetachableObject {
                let detached = detachable.detached() as! Element
                result.append(detached)
            } else {
                result.append($0) //Primtives are pass by value; don't need to recreate
            }
        }

        return result
    }

    func toArray() -> [Element] {
        return Array(self.detached())
    }
}

extension Results {
    func toArray() -> [Element] {
        let result = List<Element>()

        forEach {
            result.append($0)
        }

        return Array(result.detached())
    }
}

答案 4 :(得分:0)

在Realm 5.0.0 freeze()方法中已添加。 根据发行说明:

添加对冻结对象的支持。领域,结果,列表和对象现在具有Frozen()方法,这些方法返回对象的冻结副本。这些对象的行为类似于创建源对象的非托管深层副本。可以从任何线程读取它们,并且在对Realm进行写入时不会更新它们,但是创建冻结的对象实际上不会将数据复制到Realm之外,因此可以更快并且使用更少的内存。冻结的对象无法突变或无法观察到变化(因为它们永远不会变化)。 (PR#6427)。