SwiftUI视图未正常更新:FighterView操作后无刷新求助
问题分析与解决方案
核心问题
你的代码存在两个关键问题导致视图不更新:
@Binding无法监听引用类型内部变化:Fighter是ObservableObject(引用类型),但FighterView用@Binding var fighter: Fighter绑定它。@Binding只关注对象引用是否改变,而Fighter内部属性(如wazaari、name)修改时,对象引用并未变化,因此视图不会触发更新。Fight的@Published仅检测对象引用变化:即使Fighter内部属性修改,Fight中的@Published var fighter1: Fighter只会在fighter1的引用被替换时触发更新,无法感知其内部属性的变化。
方案一:将Fighter改为值类型(推荐)
SwiftUI对值类型的属性变化有天然的更新支持,这是最符合SwiftUI设计理念的解决方案:
// 修改Fighter为struct值类型 struct Fighter { var name: String = "" var wazaari = 0 /* 其他变量 */ mutating func reset() { // 重置所有默认值 } } // Fight类无需修改,@Published会自动检测值类型的变化 class Fight: ObservableObject { @Published var fighter1: Fighter @Published var fighter2: Fighter init(fighter1: Fighter, fighter2: Fighter) { self.fighter1 = fighter1 self.fighter2 = fighter2 } func resetFight() { fighter1.reset() fighter2.reset() } } // FighterView保留@Binding,值类型的属性变化会自动触发视图更新 struct FighterView: View { @Binding var fighter: Fighter var body: some View { HStack { // 移除多余的onChange,双向绑定已自动处理输入更新 TextField("Placeholder", text: $fighter.name) Button(action: { guard fighter.wazaari < 2 else { return } fighter.wazaari += 1 print(fighter.wazaari) }, label: { Text("\(fighter.wazaari)") }) .buttonStyle(PointButton()) } } }
方案二:保留Fighter为类,调整视图监听方式
如果必须保留Fighter为引用类型,需要让FighterView直接监听Fighter内部的@Published属性:
// Fighter类保持不变 class Fighter: ObservableObject { @Published var name: String = "" @Published var wazaari = 0 /* 其他变量 */ func reset() { // 重置默认值 } } // Fight类的@Published可省略(仅当需要监听fighter1/fighter2的引用替换时保留) class Fight: ObservableObject { var fighter1: Fighter var fighter2: Fighter init(fighter1: Fighter, fighter2: Fighter) { self.fighter1 = fighter1 self.fighter2 = fighter2 } func resetFight() { fighter1.reset() fighter2.reset() } } // 修改FighterView用@ObservedObject监听Fighter的内部变化 struct FighterView: View { @ObservedObject var fighter: Fighter var body: some View { HStack { TextField("Placeholder", text: $fighter.name) Button(action: { guard fighter.wazaari < 2 else { return } fighter.wazaari += 1 print(fighter.wazaari) }, label: { Text("\(fighter.wazaari)") }) .buttonStyle(PointButton()) } } } // BoardView中直接传递Fighter实例给FighterView struct BoardView: View { @StateObject var fight = Fight(fighter1: Fighter(), fighter2: Fighter()) var body: some View { NavigationStack { VStack(alignment: .leading) { TopBarView() FighterView(fighter: fight.fighter1) FighterView(fighter: fight.fighter2) BottomBarView() } } .environmentObject(fight) } }
额外优化
你代码中TextField的onChange是冗余的,$fighter.name已经实现了双向绑定,输入时会自动更新fighter的name属性,无需手动赋值。
内容的提问来源于stack exchange,提问作者C. Moulinet
相关产品推荐
相关产品推荐

