成功登录后,SwiftUI ObservedObject 未更新视图

Posted

技术标签:

【中文标题】成功登录后,SwiftUI ObservedObject 未更新视图【英文标题】:SwiftUI ObservedObject not updating view after successful login 【发布时间】:2020-08-05 16:22:01 【问题描述】:

为了在成功登录后从我的根视图显示我的内容,我尝试使用ObservedObjectEnvironmentObject,但无济于事。

例如如下:

struct RootView: View 

    @EnvironmentObject var loginManager: LoginManager

    var body: some View 
        Group 
            if loginManager.isLoggedIn 
                SegmentedView()
            
            else 
                WelcomeView()
            
        
    


class LoginManager: ObservableObject 
    
    static let shared = LoginManager()
    var cancellable = Set<AnyCancellable>()
    @Published var isLoggedIn = false

    ...
    
    func login(...) 
        ...
        // on success
        self.isLoggedIn = true
    

LoginManager 保留在SceneDelegate 中并放入环境中:

class SceneDelegate: UIResponder, UIWindowSceneDelegate 

    var window: UIWindow?
    var loginManager = LoginManager.shared
    ...

    // the view passed to window.rootUiewController via UIHostingController
    let contentView = RootView().environmentObject(loginManager)

登录后,它会直接回到我的WelcomeView。我错过了什么?

编辑

这是一个新的方面。我有一个 LoginView 的视图模型来管理日期字段中的数据。当登录按钮被按下时,我在这个视图模型中调用了一个login() 方法。

我需要在视图模型中调用两个 .sink 回调,因为我必须通过将 loading 标志设置为 false 来关闭加载指示器。

所以我不能直接调用self.isLoggedIn = true,因为我在视图模型中,而不是LoginManager。相反,我打电话给

self.loginManager.isLoggedIn = true 

我怀疑这条线不起作用。

视图模型和登录管理器之间的连接是这样完成的

@ObservedObject var loginManager = LoginManager.shared

但是,在将其转移到LoginManager 之后,我确实从那里调用self.isLoggedIn。还是不行。

我有两篇论文:

    可能是视图没有正确设置Group等。我也尝试使用@ViewBuilder等,没有区别。

    可能有两个LoginManager 实例,或者RootView 以某种方式重新初始化为isLoggedIn 为假的新实例。但我多年来一直在创建这样的 Swift 单例:

    static let shared = LoginManager()

从来没有遇到过任何问题。

如cmets中所说,我在全部切换到@EnvironmentObject时遇到另一个错误:

Fatal error: No ObservableObject of type LoginManager found. A View.environmentObject(_:) for LoginManager may be missing as an ancestor of this view.: file SwiftUI, line 0

【问题讨论】:

顺便说一句,在使用断点进行一些调试之后,似乎以true 的条件重新创建了视图,然后立即用false 销毁并再次创建。 还有其他地方可以访问 LoginManager 吗?喜欢SegmentedView 使用它还是更改isLoggedIn 属性? @mginn 否。有一个带有令牌的替代登录方案,但我现在正在测试用户名密码登录。我注意到我没有“关闭”通过导航链接从欢迎视图访问的登录视图。有时登录后视图不会重新创建或更新。 self.isLoggedIn = true 是否在主队列上执行? @Mundi,不太确定要分享什么。这基本上就是你所拥有的。我在视图中添加了一个外部 VStack 以在视图模型上添加一个调用 login 的假“登录”按钮。我用DispatchQueue.main.asyncAfter 模拟了异步登录。就是这样 【参考方案1】:

我想我得到了错误。

我认为.sink(receiveCompletion: 总是有错误,因为我所指的模板。但是无论如何都会调用完成块。

不幸的是,如果你插入一个参数error in,它永远不会是nil,而是包含类似的东西

Combine.Subscribers.Completion<module.CustomError>.finished

所以我猜,你不应该再在那里检查错误。

【讨论】:

以上是关于成功登录后,SwiftUI ObservedObject 未更新视图的主要内容,如果未能解决你的问题,请参考以下文章

成功登录后 SwiftUI Firebase 身份验证关闭视图

FireBase 登录过程后导航到主屏幕(内容视图)。 (SwiftUI)

在 2 个页面 SwiftUI 之间传递状态

以编程方式导航到 SwiftUI 中的新视图

在 SwiftUI 中更改完成视图

SwiftUI 成功后自动转到下一个视图