将Cognito身份验证状态更改发布到后台线程上的environmentObject [英] Publishing Cognito authentication state changes to environmentObject on background thread

查看:133
本文介绍了将Cognito身份验证状态更改发布到后台线程上的environmentObject的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个利用AWS Amplify / Cognito进行身份验证的SwiftUI应用程序。我创建了一个会话对象,该对象跟踪用户是否已通过身份验证。该会话对象是一个ObservableObject,已加载到environmentObject中并由不同的视图访问。它具有一个名为isLoggedIn的@Published属性。在此会话对象中,已创建一个侦听器以捕获身份验证状态的更改,这些更改将更新isLoggedIn的值。该代码将按预期进行编译和运行,但是在用户登录时尝试更新isLoggedIn属性时会生成以下运行时警告:

I am working on a SwiftUI app that utilizes AWS Amplify/Cognito for its authentication. I have created a session object that keeps track of whether a user is authenticated. This session object is an ObservableObject that is loaded into environmentObject and accessed by different views. It has a @Published property called isLoggedIn. Within this session object, a listener has been created to capture changes in authentication state which update the value of isLoggedIn. The code compiles and runs as expected but the following run time warning is generated when trying to update the isLoggedIn property when a user logs in:


不允许从后台线程发布更改;确保
通过模型更新从主线程中发布值(通过
之类的运算符进行接收)。

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.

我的问题是捕获身份验证状态并设置值的适当方法是什么,以便它通过SwiftUI的environmentObject机制发布?我可以将侦听器移至AppDelegate并从那里更新环境对象中包含的会话吗?如果是这样,您如何在视图之外访问environmentObject?还有另一种更干净的方法来获取价值并将其引入SwiftUI的environmentObjects吗?我知道我可以对Cognito / Amplify进行API调用来确定用户的身份验证状态,但这不适合SwiftUI的反应式模型,或者至少我不知道如何将其放入:)。

My question is what is the appropriate way to capture the authentication state and set the value so that is it published via the environmentObject mechanism of SwiftUI? Could I move my listener to AppDelegate and update the Session contained in the environmentObject from there? If so, how do you access environmentObjects outside of views? Is there another cleaner way of capturing the value and introducing it into SwiftUI's environmentObjects? I know I can make an API call to Cognito/Amplify to determine the authentication state of the user but that doesn't fit into the reactive model of SwiftUI or at least I don't see how to fit it in :).

下面显示的是此过程涉及的代码。第一个代码段用于Session对象。第二个示例显示将会话对象放入SceneDelegate内的enviromentObject中。最后一个片段显示了一个视图,在该视图中可以访问对象以做出渲染决定。

Shown below is the code involved in this process. The first code snippet is for the Session object. The second one shows the session object being put into an enviromentObject within the SceneDelegate. The last snippet shows a view where the object if accessed to make a rendering decision.

Session.swift

Session.swift

class Swift:ObservableObject {
@Published var firstName: String = ""
@Published var lastName: String = ""
@Published var isLoggedIn: Bool = false


init(){
    AWSMobileClient.default().addUserStateListener(self) { (userState, info) in
        switch (userState) {
        case .guest:
            self.isLoggedIn = false
        case .signedOut:
            self.isLoggedIn = false
        case .signedIn:
            self.isLoggedIn = true
        case .signedOutUserPoolsTokenInvalid:
            self.isLoggedIn = false
        case .signedOutFederatedTokensInvalid:
            self.isLoggedIn = false
        default:
            self.isLoggedIn = false
        }
    }
}

SceneDelegate.swift

SceneDelegate.swift

...
    let currentSession = Session()
    let mainTabView = MainTabView().environmentObject(currentSession)

...

查看

struct MyView: View {
@EnvironmentObject var currentSession: Session

var body: some View {
    VStack{
        if (self.currentSession.isLoggedIn) {
            Spacer()
            Text("Logged In Content")
            Spacer()
        }
        else{
            LoginJoinView()
        }
    }
}

}

推荐答案

我相信您需要在 DispatchQueue.main.async中包装任何可更改已发布属性的代码。 ,以便将更改传播到主线程上。

I believe that you need to wrap any code that changes your published properties in DispatchQueue.main.async so that the changes are propagated on the main thread.

DispatchQueue.main.async {
        switch (userState) {
        case .guest:
            self.isLoggedIn = false
        case .signedOut:
            self.isLoggedIn = false
        case .signedIn:
            self.isLoggedIn = true
        case .signedOutUserPoolsTokenInvalid:
            self.isLoggedIn = false
        case .signedOutFederatedTokensInvalid:
            self.isLoggedIn = false
        default:
            self.isLoggedIn = false
        }
}

这篇关于将Cognito身份验证状态更改发布到后台线程上的environmentObject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆