发布值更改后不会触发 onReceive

Posted

技术标签:

【中文标题】发布值更改后不会触发 onReceive【英文标题】:onReceive is not triggered after published value has changed 【发布时间】: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(),但为什么它会起作用?

【问题讨论】:

【参考方案1】:

但为什么它会起作用?

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

@ObservedObject var viewModel = AddChallengeViewModel()

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

@StateObject var viewModel = AddChallengeViewModel()

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

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

【讨论】:

以上是关于发布值更改后不会触发 onReceive的主要内容,如果未能解决你的问题,请参考以下文章

Angular 手表不会在值更改时触发

当我在渲染视图后设置该输入类型的值时,为什么输入类型的更改事件不会触发?

表单组值更改时不会触发更改检测

Stickit:如何在每个模型后触发更改事件 -> 视图更改

没有 requestLocationUpdates 不会触发 Android 地理围栏

更改谓词后,NSFetchedResultsController 的委托不会触发