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协议,然后直接遍历数组元素,确保每个闭包捕获的是当前循环的独立实例:
- 修改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 } }
- 修改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
相关产品推荐
相关产品推荐

