Once a user logs in to my app, I want to change the view from SignInView to AppShellView. The authData variable updates perfectly fine in UserViewModel once it receives data from the API (checked in UserViewModel via print statement) but this update is not being reflected in ContentView as it always shows the SignInView.
Why is authData not being updated in 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()
}
}
}
Edit:
The problem seems to be the following: While the code successfully creates the authData object in UserViewModel, it cannot share its updated state outside of UserViewModel (despite being declared as @Published) no matter in which other struct or view I try to use it.
2
Answers
It is possible that the code execution may exit the URLSession request completion handler in the following two places without updating ‘userViewModel.authData’.
To evaluate this hypothesis, add print or debugger breakpoint.
Additionally, the URLSession request completion handler executes the code on a non-main thread, so the line
should be wrapped by DispatchQueue.main.async.
It’s possible that the bug resides here in the else clause:
as it passes through it due to the url your are using is in
http
which leads to an error of:The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
you can solve it by
Using HTTPS instead or add this domain to Exception Domains in your Info.plist
.Hope this helps , good luck!