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

SwiftUI视图未正常更新:FighterView操作后无刷新求助

问题分析与解决方案

核心问题

你的代码存在两个关键问题导致视图不更新:

  1. @Binding无法监听引用类型内部变化:Fighter是ObservableObject(引用类型),但FighterView用@Binding var fighter: Fighter绑定它。@Binding只关注对象引用是否改变,而Fighter内部属性(如wazaari、name)修改时,对象引用并未变化,因此视图不会触发更新。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 10:28:12