在后台线程上将 Cognito 身份验证状态更改发布到 environmentObject
Publishing Cognito authentication state changes to environmentObject on background thread
我正在开发一个使用 AWS Amplify/Cognito 进行身份验证的 SwiftUI 应用程序。我创建了一个会话对象,用于跟踪用户是否已通过身份验证。这个会话对象是一个 ObservableObject,它被加载到 environmentObject 中并被不同的视图访问。它有一个名为 isLoggedIn 的 @Published 属性。在这个会话对象中,已经创建了一个侦听器来捕获身份验证状态的变化,这些变化会更新 isLoggedIn 的值。代码按预期编译和 运行s 但当用户登录时尝试更新 isLoggedIn 属性 时会生成以下 运行 时间警告:
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 中包含的 Session 吗?如果是这样,您如何访问视图之外的环境对象?是否有另一种更简洁的方法来捕获值并将其引入 SwiftUI 的 environmentObjects?我知道我可以 API 调用 Cognito/Amplify 来确定用户的身份验证状态,但这不适合 SwiftUI 的反应模型,或者至少我不知道如何适合它在 :)。
下面显示的是此过程中涉及的代码。第一个代码片段是针对 Session 对象的。第二个显示会话对象被放入 SceneDelegate 中的 enviromentObject。最后一个片段显示了一个视图,其中访问对象以做出渲染决定。
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
...
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
中,以便在主线程上传播更改。
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
}
}
我正在开发一个使用 AWS Amplify/Cognito 进行身份验证的 SwiftUI 应用程序。我创建了一个会话对象,用于跟踪用户是否已通过身份验证。这个会话对象是一个 ObservableObject,它被加载到 environmentObject 中并被不同的视图访问。它有一个名为 isLoggedIn 的 @Published 属性。在这个会话对象中,已经创建了一个侦听器来捕获身份验证状态的变化,这些变化会更新 isLoggedIn 的值。代码按预期编译和 运行s 但当用户登录时尝试更新 isLoggedIn 属性 时会生成以下 运行 时间警告:
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 中包含的 Session 吗?如果是这样,您如何访问视图之外的环境对象?是否有另一种更简洁的方法来捕获值并将其引入 SwiftUI 的 environmentObjects?我知道我可以 API 调用 Cognito/Amplify 来确定用户的身份验证状态,但这不适合 SwiftUI 的反应模型,或者至少我不知道如何适合它在 :)。
下面显示的是此过程中涉及的代码。第一个代码片段是针对 Session 对象的。第二个显示会话对象被放入 SceneDelegate 中的 enviromentObject。最后一个片段显示了一个视图,其中访问对象以做出渲染决定。
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
...
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
中,以便在主线程上传播更改。
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
}
}