SwiftUI+Realm开发Todo应用:无法在写入事务外修改List问题
SwiftUI + Realm Todo应用关联问题及解决过程
我正在通过开发Todo应用学习SwiftUI和Realm,现有两个数据对象:Todo和Task,要求一个Todo必须关联一个Task,因此首次创建Todo前必须先创建Task:

添加任务后,任务会显示在“Task”选择器中,初始实现代码如下:
struct CreateTodoView: View { @State private var task: TaskObject? @ObservedResults(TaskObject.self) var tasks @ObservedResults(Todo.self) var todos var body: some View { // … Picker("Task", selection: $task) { Text("- Select Task -").tag(nil as TaskObject?) ForEach(tasks, id: \.self) { task in Text(task.name).tag(task as TaskObject?) } } Button { guard let task else { return } let todo = Todo() todo.date = //… $todos.append(todo) // 1. 此代码可行 try! realm.write { task.todos.append(todo) } // 2. 此代码无效 } label: { Text("Save") } // … } }
我按照Realm文档使用@ObservedResults(标记1)将新创建的Todo添加到todos集合中,这部分正常工作,但同时尝试将该Todo关联到选中的Task时,执行标记2的代码出现以下错误:
cannot modify List outside of a write transaction.
我猜测这可能是因为使用了不同的Realm实例,但想知道有没有简便方法,能在继续使用便捷的@ObservedResults的前提下实现需求?另外@ObservedObject不支持可选类型,没法在选中任务时赋值给该属性。
更新1:调整代码后仍报错
我根据建议修改了代码,仅将任务列表声明为@ObservedResults,尝试创建新Todo并直接添加到选中的Task中,但还是出现相同错误:
struct TodoView: View { //@ObservedResults(Todo.self) var todos @ObservedResults(TaskObject.self) var tasks @Environment(\.dismiss) var dismiss @State private var todoName: String = "" @State private var selectedTask: TaskObject? var body: some View { Form { TextField(text: $todoName) { Text("Name") } Picker("Task", selection: $selectedTask) { Text("No Task").tag(Optional<TaskObject>(nil)) ForEach(tasks, id: \.self) { task in Text(task.name).tag(Optional<TaskObject>(task)) } } if let task = selectedTask { Text("Selected task: \(task.name)") } Button { let todo = Todo(name: todoName) if let task = selectedTask { task.todos.append(todo) } //$todos.append(todo) dismiss() } label: { Text("Save") } .disabled(selectedTask == nil) } } }
更新2:找到可行解决方案
最终我找到了一个可行的实现方式,以下是Button的动作部分代码:
Button { let todo = Todo(name: todoName) if let task = selectedTask, let thawed = task.thaw(), let realm = thawed.realm { try! realm.write { thawed.todos.append(todo) } } //$todos.append(todo) dismiss() }
看来我得深入学习Realm的相关知识了:-)
内容的提问来源于stack exchange,提问作者Heuristic
相关产品推荐
相关产品推荐

