如何将 Realm 与 SwiftUI 表单一起使用

How to use Realm with SwiftUI forms

Terminating app due to uncaught exception 'RLMException', reason: 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.'

对托管对象的所有更改(添加、修改和删除)都必须在写入事务中完成。例如,

// Update an object with a transaction
try! realm.write {
    author.name = "Thomas Pynchon"
}

可以使一个Realm子class符合ObservableObject。但是,我看不到如何在 SwiftUI 中使领域属性可更新。下面的领域 属性 示例。

@objc dynamic var myName: String = "Adam"

Realm 基于@objc 动态变量自动设置模式。我看不到在领域 属性 上获取 @Published 的方法。 SwiftUI 将呈现一个 TextField,但在编辑该值时崩溃。

TextField("Quantity (\(shoppingItem.myUnit!.myName))", value: $shoppingItem.stdQty, formatter: basicFormat)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .keyboardType(.numbersAndPunctuation)

有什么方法可以将 SwiftUI 状态更改包装在 Realm 写入事务中吗?

考虑如下所示的领域 属性,stdQty。它只能在写入事务中更改。

import RealmSwift
import Combine

class ShoppingItems: Object, ObservableObject    
    let objectWillChange = PassthroughSubject<Void, Never>()
    @objc dynamic var stdQty: Double = 1

如果没有原问题中的错误,您无法绑定 stdQty。但是,您可以创建一个可以绑定的计算变量。

    var formQty: Double {
        get {
            return stdQty
        } 
        set {
            objectWillChange.send()
            if let sr = self.realm {
                try! sr.write {
                    stdQty = newValue
                }
            }
        }
    }

绑定计算变量工作正常。

TextField("Quantity (\(shoppingItem.myUnit!.myName))", value: $shoppingItem.formQty, formatter: basicFormat)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .keyboardType(.numbersAndPunctuation)

回答限制:objectWillChange 仅由计算变量触发。表单中的更改会反映在表单中。领域中的更改尚未触发 Combine objectWillChange。

另一种方法是使用自定义绑定,当设置 属性 时,打开一个事务并将数据保存到领域。

TextField("Quantity (\(shoppingItem.myUnit!.myName))",
          value: Binding(get: {shoppingItem.stdQty},
            set: {(value) in
                //if your state property is in a view model, all this code could be like viewModel.saveData(newMessage: value)
                let realm = try! Realm()
                try! realm.write {
                    shoppingItem.stdQty = value
                }
            }),
          formatter: basicFormat)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .keyboardType(.numbersAndPunctuation)

这将在每个插入的角色上保存到领域