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

SwiftUI List添加数据触发NSTableView代理重入警告问题排查

问题原因分析

你的代码触发警告的核心问题有两个:

  • 错误的数组更新逻辑:每次点击按钮时,你直接用新的Rows实例替换了整个sections数组,而非修改数组中已存在的元素。这会让SwiftUI误以为原来的Section被移除、新的Section被添加,无法正确跟踪Section的身份变化。
  • ForEach使用不稳定的标识:外层ForEach采用id: \.self作为标识,但Rows是Hashable类型,当内部rows数组变化时,整个Rows实例的哈希值会改变,导致SwiftUI无法识别这是同一个Section的更新,而是重复创建/销毁Section视图。
修复方案

方案1:修改现有Section的内容(推荐)

将Rows的rows改为可变属性,直接更新数组中已有元素的内容,同时给外层ForEach使用稳定的id(即Rows的id属性):

struct ContentView: View {
  struct Rows: Hashable {
    let id: String
    var rows: [String] // 改为var,支持直接修改
  }

  @State var sections = [
    Rows(id: UUID().uuidString, rows: [])
  ]

  var body: some View {
    VStack {
      Button("Add Row") {
        guard var lastSection = sections.last else { return }
        lastSection.rows.append(UUID().uuidString)
        sections[sections.count - 1] = lastSection
      }
      List {
        // 使用稳定的id: \.id,而非\.self
        ForEach(sections, id: \.id) { section in
          Section(section.id) {
            ForEach(section.rows, id: \.self) { row in
              Text(row)
            }
          }
        }
      }
    }
  }
}

方案2:保持不可变结构的正确更新方式

如果要保持Rows的rows为不可变的let属性,可以替换数组中对应位置的元素,同样使用稳定的id标识:

struct ContentView: View {
  struct Rows: Hashable {
    let id: String
    let rows: [String]
  }

  @State var sections = [
    Rows(id: UUID().uuidString, rows: [])
  ]

  var body: some View {
    VStack {
      Button("Add Row") {
        guard let lastSection = sections.last else { return }
        let updatedSection = Rows(id: lastSection.id, rows: lastSection.rows + [UUID().uuidString])
        // 替换数组最后一个元素,而非整个数组
        sections[sections.count - 1] = updatedSection
      }
      List {
        ForEach(sections, id: \.id) { section in
          Section(section.id) {
            ForEach(section.rows, id: \.self) { row in
              Text(row)
            }
          }
        }
      }
    }
  }
}
关键注意点
  • 使用id: \.id作为ForEach的标识,确保Section的身份由固定的id跟踪,不受内部数据变化影响。
  • 更新数组时,针对具体元素修改或替换,而非替换整个数组,让SwiftUI能正确识别是视图更新而非新增/删除视图。

内容的提问来源于stack exchange,提问作者Ilias Karim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:40:45