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
中的challengeManager
和ContentView
中的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)的已发布属性?的主要内容,如果未能解决你的问题,请参考以下文章