SwiftUI:如何使用位置管理器类的已发布属性更新一个类(ObservableObject)的已发布属性?

Posted

技术标签:

【中文标题】SwiftUI:如何使用位置管理器类的已发布属性更新一个类(ObservableObject)的已发布属性?【英文标题】:SwiftUI: How to update published property of one class (ObservableObject) with published property of a location manager class? 【发布时间】: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 没有改变。 有人可以告诉我我做错了什么吗? 谢谢!

【问题讨论】:

【参考方案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 内部的位置,而不是相反

以上是关于SwiftUI:如何使用位置管理器类的已发布属性更新一个类(ObservableObject)的已发布属性?的主要内容,如果未能解决你的问题,请参考以下文章

DriverManager 驱动管理器类简介 JDBC简介

在 ForEach 循环中绑定时,如何阻止 SwiftUI TextField 失去焦点?

在没有屏幕管理器类的情况下在 Python 中更改屏幕

SwiftUI 视图不会为具有子类的已发布对象更新

如何在活动中使用位置查找器类。 [复制]

获取 SwiftUI 中 ScrollView 的当前位置?