Публикация изменений состояния аутентификации Cognito в environmentObject в фоновом потоке - PullRequest
0 голосов
/ 08 октября 2019

Я работаю над приложением SwiftUI, которое использует AWS Amplify / Cognito для своей аутентификации. Я создал объект сеанса, который отслеживает, аутентифицирован ли пользователь. Этот объект сеанса является ObservableObject, который загружается в environmentObject и доступен для различных представлений. У него есть свойство @Published, которое называется isLoggedIn. В этом объекте сеанса был создан прослушиватель для регистрации изменений в состоянии аутентификации, которые обновляют значение isLoggedIn. Код компилируется и выполняется должным образом, но при попытке обновить свойство isLoggedIn при входе пользователя в систему генерируется следующее предупреждение:

Публикация изменений из фоновых потоков не допускается;Обязательно публикуйте значения из основного потока (через операторы, такие как receive (on :)), при обновлении модели.

Мой вопрос заключается в том, как правильно записать состояние аутентификации и установить значение такто есть он публикуется через механизм environmentObject SwiftUI? Могу ли я переместить мой слушатель в AppDelegate и оттуда обновить сеанс, содержащийся в environmentObject? Если да, то как вы получаете доступ к environmentObjects за пределами представлений? Есть ли другой более чистый способ получения значения и его введения в объекты SwiftUI environmentObjects? Я знаю, что могу сделать вызов API для Cognito / Amplify, чтобы определить состояние аутентификации пользователя, но это не вписывается в реактивную модель SwiftUI или, по крайней мере, я не вижу, как это вписать :).

Ниже показан код, участвующий в этом процессе. Первый фрагмент кода предназначен для объекта Session. Второй показывает объект сеанса, помещаемый в объект enviromentObject в SceneDelegate. Последний фрагмент показывает представление, где объект, если к нему обращаются, чтобы принять решение о рендеринге.

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()
        }
    }
}

}

1 Ответ

1 голос
/ 08 октября 2019

Я считаю, что вам нужно обернуть любой код, который изменяет ваши опубликованные свойства в 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
        }
}
...