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

为何SwiftUI中数据遵循Equatable时ForEach无法触发视图更新

问题原因

核心问题出在你自定义的Equatable实现逻辑不完整,误导了SwiftUI的视图差分机制,导致框架判定卡片数据没有变化,跳过了视图刷新。

  • SwiftUI更新ForEach渲染的网格/列表时,会对遵循Equatable的列表元素做等值校验:如果新旧位置上的元素判定为相等,就直接复用已渲染的旧子视图,不会用新数据重绘;只有判定元素不相等时,才会刷新对应子视图。
  • 你实现的==方法只对比了Card的id属性,完全没有校验isFaceUp、isMatched、content这些直接决定UI展示效果的属性。
  • 点击卡片调用choose方法修改isFaceUp时,新旧版本的卡片id完全一致,按照你写的相等规则,SwiftUI会认为这张卡片没有任何改动,自然不会更新对应的CardView。

至于移除Equatable遵循后视图恢复正常,原因也很简单:Card本身是结构体,当你不手动实现Equatable时,SwiftUI做差分校验会自动对比它的所有存储属性,能正确识别到isFaceUp的改动,就会正常触发视图刷新。

修复方案

两种方案选一个即可:

  1. 补全Equatable的判断逻辑,把所有影响UI展示的属性都加入对比:
static func == (lhs: MemoryGame<CardContent>.Card, rhs: MemoryGame<CardContent>.Card) -> Bool {
    lhs.id == rhs.id &&
    lhs.isFaceUp == rhs.isFaceUp &&
    lhs.isMatched == rhs.isMatched &&
    lhs.content == rhs.content
}
  1. 如果你没有特殊的等值判断需求,直接删掉手动写的Equatable遵循声明和自定义==方法,让系统自动为结构体合成Equatable逻辑即可——系统自动生成的==默认会对比所有存储属性,不会出现属性漏判的问题。

额外说明:你当前choose方法里用传入的card参数找索引的逻辑,在仅对比id的Equatable实现下是能正常工作的,问题完全出在视图更新的差分环节,和索引查找逻辑无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:33:25