【问题标题】:SwiftUI: How to update published property of one class (ObservableObject) with published property of a location manager class?SwiftUI:如何使用位置管理器类的已发布属性更新一个类(ObservableObject)的已发布属性?
【发布时间】:2021-08-15 17:29:36
【问题描述】:

我想用从 LocationManager 传入的数据更新我的 ChallengeManager 类的 Published 属性。 以下是相关位的简化代码:

位置管理器

final class LocationManager: NSObject, ObservableObject {
    var challengeManager = ChallengeManager()
    ...
    //a func called from locationManager delegate converts the region to an instance of an Area object then calls a method on the ChallengeManager class like this:
    
    challengeManager.loadChallenge(for: activeArea)
...

挑战经理

final class ChallengeManager: ObservableObject {
   @Published var isShowingChallenge = false
   @Published var challengeToDisplay: Challenge?

func loadChallenge(for area: Area) {
   if let challenge = area.challenge { //gets challenge property of area object
      self.challengeToDisplay = challenge
      self.isShowingChallenge = true
   }
}

最后是 ContentView:

struct ContentView: View {
   @ObservedObject var challengeManager = ChallengeManager()
...

(老实说,我可以通过在视图中为 LocationManager 添加一个 ObservedObject 然后将值传递到那里的函数中来获得我想要的结果。但我不喜欢这样做的想法多个视图。而且我还希望 loadChallenge() 做更多繁重的工作。在我看来,它应该是唯一的事实来源。不是吗?)

问题:

如果我尝试访问 ContentView 中的 challengeManager.challengeToDisplay,则该值始终为 nil。 loadChallenge() 函数中的打印语句告诉我来自 locationManager 的值被正确接收。但是@Published var challengeToDisplay 没有改变。 有人可以告诉我我做错了什么吗?
谢谢!

【问题讨论】:

    标签: swiftui property-wrapper


    【解决方案1】:
    @ObservedObject var challengeManager = ChallengeManager()
    

    这是创建ChallengeManager 的新实例,它不会是您在LocationManager 中处理的实例。

    您应该在实例化 ContentView 时传入挑战管理器,而不是为属性提供默认值。

    【讨论】:

    • 感谢您的建议,但正如我在对@vadian 的评论中提到的那样(他提出了类似的观察),它并没有完全奏效。
    【解决方案2】:

    LocationManager 中的challengeManagerContentView 中的challengeManager 是两个不同的实例。它们不相关。您必须使用相同的实例。

    约定是

    • @StateObject 创建一个对象并拥有它

      @StateObject var challengeManager = ChallengeManager()
      
    • @ObservedObject 不创建和拥有对象,它将通过视图层次结构传递。

      @ObservedObject var challengeManager : ChallengeManager
      

    您还可以在视图层次结构的开头使用@EnvironmentObject

    旁注:

    SwiftUI 比 Swift 更依赖非可选参数。对于已发布的挑战,此枚举与关联类型(如果更类似于 SwiftUI)

    enum ChallengeState {
        case idle, display(Challenge)
    }
    

    final class ChallengeManager: ObservableObject {
       @Published var challengeState : ChallengeState = .idle
    
    func loadChallenge(for area: Area) {
       if let challenge = area.challenge { //gets challenge property of area object
          challengeState = .display(challenge)
       } else {
          challengeState = .idle
       }
    }
    

    在状态上查看switch

    【讨论】:

    • 感谢您的帮助。我尝试了您的建议,但仍然无法正常工作。正如您正确指出的那样,两个类中的 challengeManager 是不一样的。所以现在我认为问题在于我创建 challengeManager 并在 LocationManager 类中调用其方法的方式。有没有一种简单的方法可以将同一个实例传递给 LocationManager?
    • 如果挑战取决于位置,则检索 ChallengeManager 内部的位置,而不是相反
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2021-02-27
    • 2018-01-24
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多