为啥在 SwiftUI ObservableObject 中没有触发 @Published 值?

Posted

技术标签:

【中文标题】为啥在 SwiftUI ObservableObject 中没有触发 @Published 值?【英文标题】:Why does the @Published value not get triggered in SwiftUI ObservableObject?为什么在 SwiftUI ObservableObject 中没有触发 @Published 值? 【发布时间】:2020-08-20 07:04:51 【问题描述】:

我创建了以下人为的示例来演示我的问题。在这段代码中,我期望 TextField 用“Test Company X”初始化,其中 X 是基于 ObservableObject ViewModel 的视图深度。这是真的,并且仅适用于第一个视图。后续视图在初始外观时不会获得发布的值。但是,当您返回视图和 onAppear 触发器时,它确实会被初始化。为什么 TextField 在第二个和后续视图上没有正确初始化?

class TestViewModel: ObservableObject 
    @Published var companyName: String = ""
    
    func load(_ viewDepth: Int) 
        debugPrint("load: \(viewDepth)")
        
        // Mimic a network request to get data
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) 
            debugPrint("publish: \(viewDepth)")
            self.companyName = "Test Company \(viewDepth)"
        
    


struct TestFormView: View 
    
    var viewDepth: Int
    @Binding var companyName: String
    @State private var navigateToNextView: Bool = false
    
    var body: some View 
        VStack(alignment: .leading, spacing: 3) 
            
            TextField("Company name", text: $companyName)
                .padding()
                .background(
                    RoundedRectangle(cornerRadius: 5)
                        .strokeBorder(Color.primary.opacity(0.5), lineWidth: 3)
                )
            
            Button.init("NEXT") 
                self.navigateToNextView = true
            
            .frame(maxWidth: .infinity)
            .foregroundColor(Color.primary)
            .padding(10)
            .font(Font.system(size: 18,
                        weight: .semibold,
                        design: .default))
                .background(Color.secondary)
            .cornerRadius(Sizes.cornerRadius)
            
            NavigationLink(destination: TestView(viewDepth: viewDepth + 1), isActive: $navigateToNextView) 
                EmptyView()
            
            .isDetailLink(false)
            
            Spacer()
        
    


struct TestView: View 
    @ObservedObject var viewModel = TestViewModel()
    var viewDepth: Int
    
    var body: some View 
        VStack 
            TestFormView(viewDepth: viewDepth, companyName: $viewModel.companyName)
        
        .onAppear(perform: 
            self.viewModel.load(self.viewDepth)
        )
        .navigationBarTitle("View Depth \(viewDepth)")
        .padding()
    


struct TestNavigationView: View 
    
    @State private var begin: Bool = false
    
    var body: some View 
        NavigationView 
            VStack 
                if begin 
                    TestView(viewDepth: 1)
                 else 
                    Button.init("BEGIN") 
                        self.begin = true
                    
                    .frame(maxWidth: .infinity)
                    .foregroundColor(Color.primary)
                    .padding(10)
                    .font(Font.system(size: 18,
                                weight: .semibold,
                                design: .default))
                        .background(Color.secondary)
                    .cornerRadius(Sizes.cornerRadius)
                
            
        
    

【问题讨论】:

【参考方案1】:

您的模型已重新创建(由于 NavigationLink 的当前性质)

SwiftUI 2.0

修复很简单 - 专门为此目的使用 StateObject

struct TestView: View 
    @StateObject var viewModel = TestViewModel()

   // .. other code

【讨论】:

感谢您抽出宝贵时间查看我的问题。 @StateObject 仅在 ios 14 中可用,是否可以在 iOS 13 中修复此问题?

以上是关于为啥在 SwiftUI ObservableObject 中没有触发 @Published 值?的主要内容,如果未能解决你的问题,请参考以下文章

ListView 的三种数据绑定方式

SwiftUI:为啥 ObservedObject 在 AppDelegate 中不起作用?

为啥修饰符顺序在 SwiftUI 中很重要? [复制]

为啥 EmptyView() 不能在带有 SwiftUI 的 WatchOS 上工作?

为啥此 SwiftUI 代码在目标屏幕中显示“空”?

为啥我不能在 SwiftUI 中使用 append 创建数组