SwiftUI @ObservedObject值变更时抽离子视图未触发更新问题
问题原因
该UI不刷新的核心问题出在Card结构体的Equatable协议实现逻辑上:
- 自定义的
Card.==方法仅对id属性做了相等判断,没有将isFaceUp、isMatched、content这类直接影响UI展示的属性纳入比较范围。 - 当卡片UI内联写在
ForEach闭包中时,SwiftUI可直接追踪@ObservedObject标记的viewModel属性变化,自动触发对应UI的重绘。 - 当卡片逻辑抽离为独立的
CardView组件后,ForEach为了优化渲染性能,会先通过Equatable协议判断传入子视图的card参数是否发生变化:由于现有相等逻辑仅校验id,即使isFaceUp属性已经被修改,ForEach仍会判定传入的card参数和之前完全一致,不会触发CardView的重绘,因此看不到卡片翻转的UI更新。
修复方案
选择任意一种方案即可解决问题:
- 方案1(改动最小,适配现有代码结构):补全
Card结构体的相等判断逻辑,将所有影响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 }
- 方案2:调整
CardView的参数传递方式,使用@Binding绑定卡片值,而非直接传入不可变的结构体副本:- 首先修改
CardView的属性定义:
struct CardView: View { @Binding var card: MemoryGame<String>.Card // 其余body内的渲染逻辑保持不变 }- 在
ContentView的ForEach循环中,向CardView传入卡片的绑定引用,同时对应调整点击事件中choose方法的调用逻辑即可。
- 首先修改
内容的提问来源于stack exchange,提问作者tweezerticle
相关产品推荐
相关产品推荐

