SwiftUI:LotView在ResultView中无法显示抽签结果的问题
SwiftUI签文App ResultView无法显示抽签结果问题排查与解决
问题描述
App流程为 HomeView → PrayerView → PaymentView → ResultView:
- 在PrayerView点击「抽签」按钮,调用
drawLot()方法从Core Data抽取签文,PrayerView内的LotView可正常展示抽签结果 - 完成PaymentView支付流程进入ResultView后,同款LotView仅显示默认空白/0值,无法呈现已抽取的签文结果
附ResultView代码:
import SwiftUI import CoreData struct ResultView: View { // 設置 ResultViewModel 的環境對象 @ObservedObject var viewModel: ResultViewModel @ObservedObject var lotViewModel: LotViewModel @ObservedObject var prayerViewModel: PrayerViewModel var container: NSPersistentContainer init(container: NSPersistentContainer) { self.container = container lotViewModel = LotViewModel(container: container) prayerViewModel = PrayerViewModel(container: container) viewModel = ResultViewModel(container:container) } var body: some View { VStack { // 顯示籤詩相關屬性 LotView(viewModel: lotViewModel) .padding()// 在此處添加 LotView // 顯示吉凶和分析內容 Text("吉凶:\(viewModel.lotViewModel.luckLevel)") .font(.headline) .padding(.top, 20) Text("分析內容:\(lotViewModel.analysis)") .font(.headline) .multilineTextAlignment(.center) .padding(.horizontal, 20) .padding(.top, 20) // 顯示對應問題種類的屬性內容 VStack { //Text("\(viewModel.selectedCategory):") //.font(.headline) // .fontWeight(.bold) // .padding(.top, 20) if viewModel.selectedCategory == "願望" { Text(lotViewModel.wish) } else if viewModel.selectedCategory == "疾病" { Text(lotViewModel.illness) } else if viewModel.selectedCategory == "盼望的人" { Text(lotViewModel.person) } else if viewModel.selectedCategory == "遺失物" { Text(lotViewModel.lostItem) } else if viewModel.selectedCategory == "搬家" { Text(lotViewModel.moving) } else if viewModel.selectedCategory == "蓋新居" { Text(lotViewModel.newHome) } else if viewModel.selectedCategory == "嫁娶" { Text(lotViewModel.marriage) } else if viewModel.selectedCategory == "交往" { Text(lotViewModel.relationship) } else if viewModel.selectedCategory == "旅行" { Text(lotViewModel.travel) } else if viewModel.selectedCategory == "結親緣" { Text(lotViewModel.family) } } .padding(.horizontal, 20) Spacer() // 點擊返回主畫面的按鈕 /*NavigationStack{ VStack { Button(action: { viewModel.showHomeView() }) { Text("返回") .font(.headline) .foregroundColor(.white) .padding() .frame(maxWidth: .infinity) .background(Color.blue) .cornerRadius(10) .padding(.horizontal, 20) .padding(.bottom, 50) } } .navigationDestination(isPresented:$viewModel.isPresentingHomeView){ HomeView(selectedGod: "玄天上帝", container: container) } }*/ } } } struct ResultView_Previews: PreviewProvider { static var previews: some View { let container = NSPersistentContainer(name: "MyAppDataModel") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error { fatalError("Failed to load Core Data stack: \(error)") } }) return ResultView(container:container) } }
问题根源
ResultView的init方法中重新创建了LotViewModel、PrayerViewModel实例,而非复用PrayerView中已经执行过drawLot()的ViewModel实例。新实例处于初始状态,自然没有已抽取的签文数据。
另外代码中同时存在lotViewModel和viewModel.lotViewModel,说明数据持有不统一,进一步导致视图展示数据不一致。
解决方案
核心逻辑是跨视图传递已完成抽签的ViewModel实例,而非每次新建。
1. 修改ResultView初始化方式
移除内部创建ViewModel的代码,改为从外部传入已初始化完成的实例:
struct ResultView: View { @ObservedObject var viewModel: ResultViewModel @ObservedObject var lotViewModel: LotViewModel @ObservedObject var prayerViewModel: PrayerViewModel var container: NSPersistentContainer // 直接接收外部传入的ViewModel实例 init( container: NSPersistentContainer, lotViewModel: LotViewModel, prayerViewModel: PrayerViewModel, viewModel: ResultViewModel ) { self.container = container self.lotViewModel = lotViewModel self.prayerViewModel = prayerViewModel self.viewModel = viewModel } // body代码保持不变 }
2. 跳转时传递正确的ViewModel实例
在PaymentView跳转到ResultView的位置,传入PrayerView中已执行drawLot()的LotViewModel实例:
// 假设PaymentView持有PrayerView传递过来的ViewModel引用 NavigationLink(destination: ResultView( container: container, lotViewModel: self.lotViewModel, // 复用已有实例 prayerViewModel: self.prayerViewModel, viewModel: ResultViewModel(container: container) )) { Text("完成支付查看结果") }
3. 优化数据一致性(可选)
如果ResultViewModel需要依赖LotViewModel的数据,可在ResultViewModel初始化时传入LotViewModel,避免重复持有:
class ResultViewModel: ObservableObject { let lotViewModel: LotViewModel let container: NSPersistentContainer @Published var selectedCategory: String = "" init(container: NSPersistentContainer, lotViewModel: LotViewModel) { self.container = container self.lotViewModel = lotViewModel } // 其他业务逻辑 }
对应调整ResultView的初始化参数,确保数据来源统一。
关键注意事项
@ObservedObject实例若在视图内部新建,每次视图刷新都会重新初始化,导致数据丢失- 跨视图共享状态时,必须传递同一个ViewModel实例,或使用
@EnvironmentObject实现全局共享(需匹配App架构) - 确保LotViewModel中存储签文结果的属性标记为
@Published,才能触发视图响应数据更新
内容的提问来源于stack exchange,提问作者Lotloy
相关产品推荐
相关产品推荐

