一旦用户登录到我的应用程序,我想将视图从SignInView更改为AppShellView。authData变量在UserViewModel中一旦从API接收到数据(通过print语句在UserViewModel中检查)就会完美地更新,但是这个更新没有反映在ContentView中,因为它总是显示SignInView。
为什么authData没有在ContentView中更新?
UserViewModel:
import SwiftUI
struct LoginRequestBody: Codable {
let email: String
let password: String
}
struct AuthData: Codable {
let token: String
let loggedInUser: User
}
class UserViewModel: ObservableObject {
// MARK: - PROPERTIES
@Published var authData: AuthData?
// MARK: - FUNCTIONS
func signIn(email: String, password: String) {
guard let url = URL(string: "http://localhost:4000/api/users/login") else {
return
}
let body = LoginRequestBody(email: email, password: password)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONEncoder().encode(body)
URLSession.shared.dataTask(with: request) { [self] data, response, error in
guard let data = data, error == nil else {
return
}
guard let loginResponse = try? JSONDecoder().decode(AuthData.self, from: data) else {
return
}
self.authData = loginResponse
if let encoded = try? JSONEncoder().encode(self.authData) {
let defaults = UserDefaults.standard
defaults.set(encoded, forKey: "authData")
}
}.resume()
}
}
ContentView:
import SwiftUI
struct ContentView: View {
@ObservedObject var userViewModel = UserViewModel()
var body: some View {
if userViewModel.authData != nil {
AppShellView()
} else {
SignInView()
}
}
}
编辑:问题似乎如下:虽然代码成功地在UserViewModel中创建authData对象,但它不能在UserViewModel之外共享其更新状态(尽管被声明为@Published),无论在哪个其他结构或视图中我尝试使用它。
代码执行可能会在以下两个地方退出URLSession请求完成处理程序,而不更新'userViewModel.authData'。
guard let data = data, error == nil else {
return
}
guard let loginResponse = try? JSONDecoder().decode(AuthData.self, from: data) else {
return
}
要评估此假设,请添加打印或调试器断点。
此外,URLSession请求完成处理程序在非主线程上执行代码,因此
行self.authData = loginResponse
应该被DispatchQueue.main.async封装。
错误可能存在于else子句中:
guard let data = data, error == nil else {
return
}
当它通过它时,由于您使用的url在http
中,导致错误:
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
可以用Using HTTPS instead or add this domain to Exception Domains in your Info.plist
来解
请注意,当您从后台线程更改UI时,您需要将
self.authData = loginResponse
部分包装在DispatchQueue.main.async {}
上。
希望这有帮助,祝你好运!