无法从 Class 更新 Published var

Posted

技术标签:

【中文标题】无法从 Class 更新 Published var【英文标题】:Unable to update Published var from Class 【发布时间】:2021-08-07 02:43:38 【问题描述】:

我有一个已发布的 var prediction:

class TrainingStatus: ObservableObject 
    @Published var isTrained: Bool = false
    @Published var modelUrl: URL = URL(fileURLWithPath: "hello")
    @Published var prediction:String = ""


我尝试在一个类中更新这个变量:

class ClassificationController: ObservableObject 
...
 func processObservations(for request: VNRequest, error: Error?) 
      DispatchQueue.main.async 
        if let results = request.results as? [VNClassificationObservation] 
          if results.isEmpty 
            print("nothing found")
           else 
              print("got a result: \(results)!")
              let top3 = results.prefix(3).map  observation in
                String(format: "%@ %.1f%%", observation.identifier, observation.confidence * 100)
              
              self.prediction = top3.joined(separator: " ")
              
              // attempt to set environment variable?
              let trainingStatus = TrainingStatus()
              trainingStatus.prediction = self.prediction
              
              print("set prediction: \(trainingStatus.prediction)")
          

并在我的 UIView 中显示这个变量:

struct SidebarView: View 
   
    @EnvironmentObject var trainingStatus: TrainingStatus
 
    
    var body: some View 
        VStack
            NavigationView
                    Section
                        Text("Trained? " + String(trainingStatus.isTrained))
                        Text("Prediction: \(trainingStatus.prediction)")
                    
                    
                
                .navigationTitle("Data")
            
            .environmentObject(modelData)
            .environmentObject(trainingStatus)
        
    

但是,尽管 prediction 的值似乎在 ClassificationController 中更新,但我的带有文本 \(trainingStatus.prediction) 的 UI 视图从未更新。

如何更新视图以获取最新发布的值?

【问题讨论】:

如您所见,您不能这样做:let trainingStatus = TrainingStatus() trainingStatus.prediction = self.prediction。阅读更多关于如何使用 ObservableObject 以及如何传递它们的信息。您想要实现的是仅使用 1 个 TrainingStatus。 @workingdog 你能推荐一些关于如何正确设置可观察对象的资源吗? 【参考方案1】:

您可以有效地利用(几乎)单例。

您首先需要更改 ObservableObject 类并添加一个新常量:

     class TrainingStatus: ObservableObject 
        @Published var isTrained: Bool = false
        @Published var modelUrl: URL = URL(fileURLWithPath: "hello")
        @Published var prediction:String = ""

        public static let shared = TrainingStatus()
    

然后您可以通过声明以下内容在其他地方访问它:

var trainingStatus = TrainingStatus.shared

现在您可以随意修改它的值。这也将在 ObservableObject 类中更新它,因此在任何其他使用它的视图中更改它。

您的用例示例:

 struct SidebarView: View 
   
    var trainingStatus = TrainingStatus.shared
 
    
    var body: some View 
        VStack
            NavigationView
                    Section
                        Text("Trained? " + String(trainingStatus.isTrained))
                        Text("Prediction: \(trainingStatus.prediction)") //This is now referencing your new shared variable of trainingStatus
                    
                    
                
                .navigationTitle("Data")
            
            .environmentObject(modelData)
            .environmentObject(trainingStatus)
        
    

要修改常量的类:

 class ClassificationController: ObservableObject 
 
 var trainingStatus = TrainingStatus.shared

...
 func processObservations(for request: VNRequest, error: Error?) 
      DispatchQueue.main.async 
        if let results = request.results as? [VNClassificationObservation] 
          if results.isEmpty 
            print("nothing found")
           else 
              print("got a result: \(results)!")
              let top3 = results.prefix(3).map  observation in
                String(format: "%@ %.1f%%", observation.identifier, observation.confidence * 100)
              
              self.prediction = top3.joined(separator: " ")
              
              // attempt to set environment variable?
              //let trainingStatus = TrainingStatus() --- no longer need this line
              trainingStatus.prediction = self.prediction //this is now changing your singleton
              
              print("set prediction: \(trainingStatus.prediction)")
          

【讨论】:

已编辑以在您提供的代码中添加示例

以上是关于无法从 Class 更新 Published var的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI @Published 属性正在 DetailView 中更新

SwiftUI iOS 14 视图不使用 @EnvironmentObject 更新 @Published 数组

来自 @Published 属性的 SwiftUI 动画从视图外部更改

SwiftUI 将 @Published var 从一个 ObservableObject 映射到另一个

类 Observable 对象 @Published 变量始终为空

SwiftUI,@Published 和 ForEach 没有更新我的视图