在 NavigationView 中加载视图的标准方法是啥,每个视图都拥有一个从 API 填充的模型?

Posted

技术标签:

【中文标题】在 NavigationView 中加载视图的标准方法是啥,每个视图都拥有一个从 API 填充的模型?【英文标题】:What's the Standard Way of Loading Views in a NavigationView where each Owns a Model that's Populated from an API?在 NavigationView 中加载视图的标准方法是什么,每个视图都拥有一个从 API 填充的模型? 【发布时间】:2020-10-16 13:35:01 【问题描述】:

我有 2 个视图:A 和 B。视图 A 有一个从 API 端点加载其数据的模型,视图 B 也是如此。

视图 A 有一个按钮,单击该按钮后会将视图 B 推入堆栈。这是执行此操作的代码:

应用:

import SwiftUI

@main
struct TempApp: App 
    var body: some Scene 
        WindowGroup 
            ViewA()
        
    

视图/模型 A:

import SwiftUI

let REQUEST_DELAY = 6.0 // to simulate(ish) a network request

struct ViewA: View 
    @ObservedObject var model: ViewAModel = ViewAModel()
    @State var shouldGoToNextView = false
    
    var body: some View 
        NavigationView 
            if (self.model.isLoaded) 
                VStack 
                    Text(self.model.data)
                        .font(.title)
                    NavigationLink(destination: ViewB(), isActive:$shouldGoToNextView) 
                        EmptyView()
                    
                    Button(action: self.shouldGoToNextView=true) 
                        Text("GO")
                            .font(.headline)
                            .foregroundColor(.white)
                            .padding()
                            .frame(width: 220, height: 60)
                            .background(Color.blue)
                            .cornerRadius(15.0)
                    
                
             else 
                Text("Not ready...")
                    .font(.title)
            
        
        .onAppear(perform: 
            self.shouldGoToNextView = false
        )
    


class ViewAModel : ObservableObject 
    var data: String = ""
    @Published var isLoaded : Bool = false
    
    init() 
        // simulate getting the data from the network
        DispatchQueue.main.asyncAfter(deadline: .now() + REQUEST_DELAY) 
            // your code here
            self.data = "All loaded fine.."
            self.isLoaded = true
        
    


struct ViewA_Previews: PreviewProvider 
    static var previews: some View 
        ViewA()
    

模型/视图 B:

import SwiftUI

struct ViewB: View 
    @ObservedObject var model: ViewBModel = ViewBModel()
    var body: some View 
        if (self.model.isLoaded) 
            Text(self.model.data)
                .font(.title)
         else 
            Text("Secondary data not ready...")
                .font(.title)
        
    


class ViewBModel: ObservableObject 
    var data: String = ""
    @Published var isLoaded: Bool = false
    
    init() 
        // simulate getting the data from the network
        DispatchQueue.main.asyncAfter(deadline: .now() + REQUEST_DELAY) 
            self.data = "Secondary model data loaded fine.."
            self.isLoaded = true
        
    


struct ViewB_Previews: PreviewProvider 
    static var previews: some View 
        ViewB()
    

此代码在运行时有效,但我有 1 个问题和 1 个问题:

问题:这是在 SwiftUI 中实现上述目标的最佳方式吗?具体来说,我不确定我是否使用 State/ObservedObject 以及 NavigationLink 和 Button 的组合来导航到另一个视图。

问题:我无法在我正在开发的真实应用中预览视图 A,因为视图 ​​A 的代码会立即(在 NavigationLink 调用中)实例化视图 B,因此模型 B 会进行网络调用以加载它的数据,这会导致错误:

更新耗时超过 5 秒

即使我延迟加载数据,上面的示例应用也能正常预览,所以我不知道为什么!

【问题讨论】:

【参考方案1】:

1- 要查看 B,使用此代码更容易:

        NavigationLink(destination: ViewB()) 
            Text("Your buttons text")
        

2- 你应该使用StateObject,而不是使用ObservedObject

3- 不使用isLoaded,您只需@Published 您的data

4- 为了能够预览这些,我建议您将它们包装在一个容器视图中,您可以在其中传递其依赖项,在这种情况下 data 是一个字符串。例如:

struct A: View 
   var viewModel = ViewModel()
   var body: some View 
        if !data.isEmpty 
          ABodyView(data: data)
        
    

 

struct ABodyView: View 
     let data: String 
      var body: some View 
         Text(data)
      


struct ABodyView_Previews: PreviewProvider 
    static let previews: some View 
        ABodyView(data: "whatever you want")
     

【讨论】:

非常感谢您的提示!我不确定我是否 100% 理解了预览提示,但我会在今天晚些时候尝试这样做,并会告诉你进展如何。 实际上将模型更改为StateObject 而不是您建议的ObservedObject 解决了我遇到的预览问题!再次感谢。

以上是关于在 NavigationView 中加载视图的标准方法是啥,每个视图都拥有一个从 API 填充的模型?的主要内容,如果未能解决你的问题,请参考以下文章

在导航视图控制器中加载特定视图

如何在 appdelegate 中加载视图?

Swiftui NavigationView 计时器延迟

快速在视图控制器中加载集合视图控制器

如何在表格视图单元格中加载内容视图?

在 Popover 中加载局部视图