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

SwiftUI视图数据同步问题:点击按钮后天数计数器不更新

解决SwiftUI中ProgressCardView与BottomSheetView数据不同步问题

问题根源

你的核心问题是两个视图使用了独立的ProgressSettings实例,导致数据无法共享:

  • ProgressCardView通过@EnvironmentObject获取全局的ProgressSettings实例
  • BottomSheetView却用@StateObject创建了本地独立实例,点击按钮修改的是这个本地实例的dayCount,自然不会同步到ProgressCardView的实例中

解决方案

要让两个视图共享同一个ObservableObject实例,需按以下步骤修改:

1. 修改BottomSheetView,改用EnvironmentObject

移除BottomSheetView中本地创建的ProgressSettings实例,通过@EnvironmentObject获取全局共享实例:

struct BottomSheetView: View {
    @Environment(\.dismiss) var dismiss
    // 替换@StateObject为@EnvironmentObject,不再本地创建实例
    @EnvironmentObject var settings: ProgressSettings

    var body: some View {
        ZStack {
            Color("background")
                .edgesIgnoringSafeArea(.all)
            VStack(alignment: .leading) {
                HStack {
                    Text("Congratulations!")
                        .padding()
                        .foregroundColor(Color.white)
                        .font(.system(size: 24, weight: .medium))
                        .italic()
                    Spacer()
                    Text("🎉")
                        .padding()
                }
                Text("Congratulations on the successful completion of today's exercise. I'll see you tomorrow. You did great! See you tomorrow!")
                    .padding()
                    .font(.system(size: 14, weight: .regular))
                    .foregroundColor(Color("grey"))
                    .lineSpacing(5)
                
                Divider()
                    .overlay(Color("grey"))

                VStack {
                    HStack {
                        Spacer()

                        Button(action: {
                            settings.dayCount += 1
                            dismiss()
                        }) {
                            Spacer()

                            Text("End Session")
                                .frame(width: 230)
                                .padding()
                                .foregroundColor(Color.white)
                                .font(.system(size: 16, weight: .medium))
                                .italic()
                                .background(Color("red"))
                                .cornerRadius(20)
                                .padding()
                            Spacer()

                        }
                    }
                }
            }
        }
    }
    
    struct BottomSheetView_Previews: PreviewProvider {
        static var previews: some View {
            // 预览时传入共享实例
            let settings = ProgressSettings()
            BottomSheetView()
                .environmentObject(settings)
        }
    }
}

2. 在父视图中统一注入共享实例

确保你的根视图(比如ContentView)创建唯一的ProgressSettings实例,并通过.environmentObject()传递给所有子视图:

struct ContentView: View {
    // 在父视图创建唯一的全局实例
    @StateObject private var settings = ProgressSettings()
    
    @State private var showBottomSheet = false
    
    var body: some View {
        VStack {
            ProgressCardView()
            
            Button("完成今日训练") {
                showBottomSheet = true
            }
            .sheet(isPresented: $showBottomSheet) {
                BottomSheetView()
            }
        }
        // 将实例注入视图环境,供所有子视图获取
        .environmentObject(settings)
    }
}

3. 验证ProgressCardView预览(可选)

你的ProgressCardView预览已经正确使用environmentObject,无需修改,但保持逻辑一致即可:

struct ProgressCardView_Previews: PreviewProvider {
    static var previews: some View {
        ProgressCardView()
            .environmentObject(ProgressSettings())
    }
}

关键原理

@EnvironmentObject的作用是从视图层级的环境中获取已注入的ObservableObject实例,确保所有使用该对象的视图共享同一个数据源。而@StateObject仅会在当前视图内部创建并持有独立实例,无法跨视图共享数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:28:11