【问题标题】:onReceive is not triggered after published value has changed发布值更改后不会触发 onReceive
【发布时间】:2021-02-21 20:22:33
【问题描述】:

关键是在成功将记录添加到数据库后(当我点击确认按钮时),应该关闭视图。问题是添加后没有关闭,.onReceive没有触发,虽然发布者PassthroughSubject发送了一个新值。有一件事:如果在单击确认按钮之前触发了警报,则视图将关闭(例如,当未填写所有字段时,将显示警告)

此外,属性viewModel.nameviewModel.name(对于TextField's)在添加记录后变为等于空字符串,尽管我没有在代码中的任何地方明确地为它们分配这样的值(就像一个新的视图模型的实例是在这些默认值所在的位置创建的)

查看:

struct AddChallengeView: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var viewModel = AddChallengeViewModel()
    
    
    var body: some View {
        Form{
            Section(header: Text("Name")){
                TextField("Type challenge name", text: $viewModel.name) //viewModel.name == "" after new record added
            }
            
            Section(header: Text("Description")){
                TextEditor(text: $viewModel.description) //viewModel.description == "" after new record added
            }
            //...
            
            Section{
                Button(action: { viewModel.addChallenge()}){
                    HStack{
                        Spacer()
                        Text("Submit").bold()
                        Spacer()
                    }
                }
            }
            
        }.alert(isPresented: $viewModel.showErrorAlert){
            Alert(title: Text("Please, set all values!"))
        }
        .onReceive(viewModel.viewDismissalModePublisher) { shouldDismiss in
        print("new value received") //not printed 
        if shouldDismiss {
            self.presentationMode.wrappedValue.dismiss()
        }
    }
        
    }
}

视图模型:

class AddChallengeViewModel: ObservableObject{
    var viewDismissalModePublisher = PassthroughSubject<Bool, Never>()
    
    private var shouldDismissView = false {
        print("sending new value") //printed
        didSet {
            viewDismissalModePublisher.send(shouldDismissView)
        }
    }
    
    @Published var showErrorAlert = false

    @Published var name = ""
    @Published var description = ""

    //...
    
    func addChallenge () {
        //...
        
        if (name != "" && description != "" && grounds.count != 0){
            Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid).collection("challenges").addDocument(data: [
                "name": "\(name)",
                "description": "\(description)",
                "grounds": grounds
            ]) { err in
                if let err = err {
                    print("Error adding document: \(err)")
                } else {
                    print("setting new value") //printed
                    self.shouldDismissView = true
                }
            }
        } else {
            showErrorAlert.toggle()
        }
    }
}

更新:我找到了解决方案。我们需要将AddChallengeView 中的@StateObject var viewModel = AddChallengeViewModel() 替换为@ObservedObject var viewModel = AddChallengeViewModel(),但为什么它会起作用?

【问题讨论】:

    标签: swift swiftui combine


    【解决方案1】:

    但为什么它会起作用?

    您很可能在NavigationView 中使用AddChallengeView(或另一个容器,在工作流程中重新创建内容),所以有

    @ObservedObject var viewModel = AddChallengeViewModel()
    

    在每次此类视图重新创建时创建 AddChallengeViewModel 类的新实例,因此之前的任何更改都将丢失。不过

    @StateObject var viewModel = AddChallengeViewModel()
    

    保留模型实例(第一次创建)并将其注入到在视图层次结构的同一位置重新创建的相同类型的新视图中。此外,新视图会收到有关同一模型的所有更改的通知。

    实际上@StateObject 属性包装器对ObservableObject 的行为与@State 对值类型的行为相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-28
      • 2016-06-27
      • 1970-01-01
      • 2016-12-29
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 2019-04-21
      相关资源
      最近更新 更多