You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI+Realm开发Todo应用:无法在写入事务外修改List问题

SwiftUI + Realm Todo应用关联问题及解决过程

我正在通过开发Todo应用学习SwiftUI和Realm,现有两个数据对象:Todo和Task,要求一个Todo必须关联一个Task,因此首次创建Todo前必须先创建Task:

New Todo

添加任务后,任务会显示在“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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 06:35:49