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

SwiftUI中如何在List的ForEach闭包内更新变量?

SwiftUI中“Cannot assign to property: 'self' is immutable”错误解决方案

问题代码

struct NotesView: View {
    @State var notesArray = [Note]()
    public var deleteid: String
    var body: some View {

        List{
            ForEach(notesArray, id: \._id) { notesArray in
                NavigationLink(destination: AddNotesView(addNotesViewIdentifier: "updateNote", id: notesArray._id, title: notesArray.title, note: notesArray.note, noteDate: notesArray.date)){
                    HStack {
                        Text(notesArray.title)
                        deleteid = notesArray._id //ERROR - Cannot assign to property: 'self' is immutable
                    }
                }
            }
        }
        .onDelete(perform: deleteNoteAtIndex)
    }
}

func deleteNoteAtIndex(at offsets: IndexSet){ APIFunctions.functions.DeleteNote(id: _id) }

错误原因

NotesView是值类型(struct),默认情况下struct的存储属性不可变;body是计算属性,其闭包内的self处于不可变上下文,因此无法直接修改deleteid这类普通存储属性。此外你的实现逻辑存在冗余——删除操作根本不需要提前存储id。

修正方案

直接在删除方法中通过索引获取要删除元素的id,无需提前维护deleteid变量。修正后的代码如下:

struct NotesView: View {
    @State var notesArray = [Note]()
    
    var body: some View {
        List{
            // 重命名循环参数避免和全局数组混淆
            ForEach(notesArray, id: \._id) { note in
                NavigationLink(destination: AddNotesView(addNotesViewIdentifier: "updateNote", id: note._id, title: note.title, note: note.note, noteDate: note.date)){
                    HStack {
                        Text(note.title)
                        // 移除多余的赋值操作
                    }
                }
            }
        }
        .onDelete(perform: deleteNoteAtIndex)
    }
    
    func deleteNoteAtIndex(at offsets: IndexSet) {
        // 获取要删除元素的索引
        guard let index = offsets.first else { return }
        let targetNote = notesArray[index]
        // 调用删除API
        APIFunctions.functions.DeleteNote(id: targetNote._id)
        // 同步更新本地数组,刷新UI
        notesArray.remove(at: index)
    }
}

补充说明

如果确实需要在View的闭包内修改某个属性,需将其声明为可绑定状态:

  • 若属性由当前View管理,使用@State标记,例如@State var deleteid: String = ""
  • 若属性由父View传递,使用@Binding标记

但在当前删除场景下,完全不需要额外维护deleteid,通过索引直接获取目标id是更简洁合理的实现方式。

内容的提问来源于stack exchange,提问作者James J Creston

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:55:27