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

Realm/SwiftUI删除笔记时触发Index 2越界崩溃问题求助

解决Realm List删除笔记时索引越界崩溃问题

问题描述

添加3条笔记后,删除第一条或第二条笔记时应用崩溃,抛出错误:Index 2 is out of bounds (must be less than 2)

崩溃原因

问题出在通过固定索引访问实时更新的Realm集合上:@ObservedResults是与Realm数据库实时同步的动态集合,当你删除元素后,集合会立即刷新,但onDelete传递的索引基于删除前的List状态,此时用该索引去访问已经更新后的notes集合,就会出现索引越界。

解决方案

1. 改用Realm原生集合删除方法

修改ViewModel的删除逻辑,直接接收IndexSet并利用@ObservedResults提供的remove(atOffsets:)方法,该方法会自动处理Realm写入和集合同步,完全避免索引不一致问题:

class NoteViewModel: ObservableObject {
    @ObservedResults(Note.self) var notes
    @Published var newNoteText: String = ""

    // 其他方法保持不变...
    
    // 替换原deleteNote方法
    func deleteNotes(at offsets: IndexSet) {
        $notes.remove(atOffsets: offsets)
    }
}

2. 简化视图中的删除调用

将List的onDelete闭包直接指向新的删除方法:

List {
    ForEach(viewModel.notes) { note in
        // 原HStack内容保持不变...
    }
    .onDelete(perform: viewModel.deleteNotes) // 直接传递方法引用
    .listRowSeparator(.hidden)
}

3. 额外优化:移除冗余Realm实例创建

原代码中手动创建Realm实例的方式可以简化,利用@ObservedResults和Realm对象的内置关联:

  • 优化addNote方法:
func addNote() {
    guard !newNoteText.isEmpty else { return }
    let note = Note()
    note.id = getNextNoteId()
    note.title = newNoteText
    note.isCompleted = false
    $notes.append(note) // 直接通过关联的集合添加
    newNoteText = ""
}
  • 优化markNoteAsCompleted方法:
func markNoteAsCompleted(id: Int) {
    guard let note = notes.first(where: { $0.id == id }) else { return }
    try! note.realm?.write {
        note.isCompleted.toggle()
    }
}

为什么原代码会崩溃

当你触发删除操作时,Realm会立即更新@ObservedResults集合。原代码中先通过notes[index]获取ID,再去数据库中查找删除,但在这个过程中,集合可能已经因为Realm的实时同步发生了变化,导致后续操作使用的索引与当前集合状态不匹配,最终触发索引越界错误。

内容的提问来源于stack exchange,提问作者Max Elmers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 03:13:15