首页 > 解决方案 > 为什么@Published 值不会在 SwiftUI ObservableObject 中被触发?

问题描述

我创建了下面的人为示例来演示我的问题。在这段代码中,我期望 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)
                }
            }
        }
    }
}

标签: iosswiftui

解决方案


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

SwiftUI 2.0

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

演示

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

   // .. other code

推荐阅读