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

SwiftUI中ForEach内Button点击始终选中最后一个Card对象问题

问题解决:SwiftUI ForEach中Button点击总是选中最后一个Card

问题原因

你遇到的问题源于SwiftUI视图闭包的延迟捕获特性:在ForEach里提前用let card = viewModel.cards[index]捕获的变量,会在视图更新时被后续循环迭代覆盖,导致所有Button的点击事件最终指向数组的最后一个Card实例。

解决方案1:通过index实时获取Card

直接在Button的action闭包里通过index访问数组元素,避免提前捕获变量:

ForEach(0..<viewModel.cards.count, id: \.self) { index in
    Button {
        // 点击时实时通过index取对应元素
        viewModel.selectedCard = viewModel.cards[index]
    } label: {
        CardView(card: viewModel.cards[index])
            .padding(.horizontal, 35)
    }
}

解决方案2:让Card遵循Identifiable,直接遍历元素

将Card改为遵循Identifiable协议,然后直接遍历数组元素,确保每个闭包捕获的是当前循环的独立实例:

  1. 修改Card类:
class Card: ObservableObject, Identifiable {
    let id = UUID() // 添加唯一标识
    @Published var name: String
    @Published var zIndex: Int
    
    init(name: String, zIndex: Int = 0) {
        self.name = name
        self.zIndex = zIndex
    }
}
  1. 修改ForEach写法:
ForEach(viewModel.cards) { card in
    Button {
        viewModel.selectedCard = card
    } label: {
        CardView(card: card)
            .padding(.horizontal, 35)
    }
}

补充说明

如果Card不需要作为ObservableObject(比如不需要监听内部属性变化),建议将其改为结构体并遵循Identifiable,值类型的特性会进一步避免引用捕获带来的问题:

struct Card: Identifiable {
    let id = UUID()
    var name: String
    var zIndex: Int
    
    init(name: String, zIndex: Int = 0) {
        self.name = name
        self.zIndex = zIndex
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:28:33