如何在 swift 中分离 realm 对象

How to detached realm objects in swift

提问人:ambassador 提问时间:10/16/2023 更新时间:10/18/2023 访问量:30

问:

我们使用 realm and 并希望分离 realm s,即:创建一个对象的静态副本,该对象是一个 swift 类/结构体,可以独立于 realm 进行传递和修改。我们需要这样做有两个主要原因:Object

  1. 将 Persistence 层完全抽象出来,因此任何文件都不需要使用 realm 甚至导入 RealmSwift 包。Object
  2. 能够传递这些对象,有时甚至跨线程传递。(Realm 对象不是线程安全的)

如何实现这一目标?

我看到了两个“解决方案”,每个解决方案都有其不理想的原因(代码见下文):

  • 方法 1领域对象映射到值类型,并手动编写所有 CRUD 操作,这些操作也在它们之间映射。这篇文章做了类似的事情。然而,这两篇文章都非常古老(4+和6+年)和过时(根据领域文档:“@Persisted声明样式取代了旧版本SDK中@objc动态声明符号。)

  • 方法 2 创建一个“DetachableObject”协议并为其创建一个符合该协议的扩展,如下所示。但是这篇文章已经有 7 年的历史了,它并没有真正解决上述原因 1Object


方法 1

public struct Publisher {
    public let identifier: Int
    public let name: String
}
final class PublisherObject: Object {
    dynamic var identifier = 0
    dynamic var name = ""
    override static func primaryKey() -> String? {
        return "identifier"
    }
}
extension Publisher: Persistable {

    public init(managedObject: PublisherObject) {
        identifier = managedObject.identifier
        name = managedObject.name
    }

    public func managedObject() -> PublisherObject {
        let publisher = PublisherObject()

        publisher.identifier = identifier
        publisher.name = name

        return publisher
    }
}

// more see: https://gist.github.com/gonzalezreal/9d297c68435b9ee12bb1b009afd41d9a

方法 2

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 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 {
            result.append($0.detached())
        }
        return result
    }

}
iOS Swift 领域

评论


答:

0赞 Jay 10/17/2023 #1

我相信你问的是 Realm 对象的非托管版本。

如果是这样,那就是这个过程:创建一个对象并持久化它

class Person: Object {
   @Persisted var name = ""
}

let p = Person()
p.name = "Jay"

try! realm.write {
   realm.add(p)
}

稍后,我们想要一个 Jay 的非托管副本 - 它不与 Realm 绑定,不实时也不反映对 Jay 的任何更改,只存在于内存中

let jay = realm.objects(Person.self).where { $0.name == "Jay" }.first!

let unmanagedJay = Person(value: p)

//unmanagedJay is not Persisted and is flexible for doing what's needed with that object

这应该满足以下要求:1) 完全抽象出持久性层,然后 2) 能够传递这些对象

我们在 macOS 应用程序中经常使用这个过程来放置一个 on 对象的非托管副本,例如,在 UI 中向用户显示的工作表,可以自由操作,而不会影响 Realm 或受 Realm 影响

而且您始终可以访问线程安全的冻结对象

冻结创建特定对象、集合、 或领域。冻结的对象、集合或领域仍存在于 磁盘,并且在传递给 其他线程。您可以在线程之间自由共享冻结的对象 无需担心线程问题。

同样@Threadsafe也可以使用属性包装器,它符合 sendable 并允许传递受线程限制的对象实例。