SwiftUI Sheet修改分数后未更新父视图玩家区域的问题求解
问题根因
你当前使用的Game、Player、Round均为值类型(struct),在sheet的ForEach中传递player给View1时实际是做了值拷贝,View1.ViewModel内修改的是副本属性,和ContentView中game.players存储的原始实例无关联,因此不会触发父视图更新。
修复方案
1. 调整数据模型为引用类型
将需要跨视图同步修改的模型改为class类型,需观测的属性添加@Published标记:
// Round.swift import SwiftUI class Round: Identifiable, ObservableObject { var id: UUID = UUID() @Published var earnedPoints: Int = 0 var completedPhase: Bool = false var selectedPhase: Int = 0 }
// Player.swift import SwiftUI class Player: Identifiable, ObservableObject { init(name: String) { self.name = name } var id: UUID = UUID() var name: String @Published var rounds: [Round] = [Round()] var score: Int { rounds.map(\.earnedPoints).reduce(0, +) } }
// Game.swift import SwiftUI class Game: Identifiable, ObservableObject { init(name: String) { self.name = name } var id: UUID = UUID() var name: String @Published var players: [Player] = [] var isMastersEdition: Bool = false }
2. 调整ContentView的属性持有方式
将game改为@StateObject持有,遍历玩家时添加@ObservedObject监听单个玩家的属性变化:
import SwiftUI struct ContentView: View { @StateObject var game: Game = Game(name: "Game #1") @State var isPresented: Bool = true var body: some View { NavigationView { List { Section(header: Text("PLAYERS")) { ForEach(game.players) { player in @ObservedObject var player = player HStack { Text(player.name) Spacer() Text("\(player.score)") } } } } .navigationTitle(game.name) } .sheet(isPresented: $isPresented) { TabView { ForEach(game.players) { player in View1(player: player) } } .tabViewStyle(PageTabViewStyle()) } .onAppear { for p in 1...3 { let player = Player(name: "Player #\(p)") game.players.append(player) } } } }
3. 调整View1及其ViewModel的实现
ViewModel中监听round的属性变化,手动触发更新通知,需导入Combine框架:
import SwiftUI import Combine struct View1: View { @ObservedObject var vm: ViewModel init(player: Player) { vm = ViewModel(player: player) } var body: some View { VStack { Spacer() Text(vm.name) Divider() Group { Stepper("Earned Points: \(vm.earnedPoints)", value: $vm.earnedPoints, in: 0...50) } .padding(.horizontal) Spacer() } } } extension View1 { class ViewModel: ObservableObject { private let player: Player private let round: Round private var cancellables = Set<AnyCancellable>() init(player: Player) { self.player = player self.round = player.rounds[0] // 监听round的属性变化,触发ViewModel的更新通知 round.objectWillChange .sink { [weak self] _ in self?.objectWillChange.send() } .store(in: &cancellables) } var name: String { player.name } var earnedPoints: Int { get { round.earnedPoints } set { round.earnedPoints = newValue } } } }
修改完成后,Stepper修改的分数会实时同步到父视图的玩家分数区域,无需等待sheet关闭才更新。
内容的提问来源于stack exchange,提问作者eleethesontai
相关产品推荐
相关产品推荐

