'How to pass data from a login service to main views in swift?
My app's login view accesses an external service to validate the user's credentials and return a swift object. The login view calls a login function here:
func login(completion: @escaping (Bool) -> Void) {
showProgressView = true
//checks with APIService
APIService.shared.login(credentials: credentials) { [unowned self](result:Result<Bool, Authentication.AuthenticationError>) in showProgressView = false
switch result {
case .success:
completion(true)
case .failure(let authError):
credentials = Credentials()
error = authError
completion(false)
}
}
}
The API service then does this:
URLSession.shared.dataTask(with: request) { data, HTTPURLResponse, Error in
typealias YourDecodedObject = [StudentClass]
if let data = data {
do {
let decodedObject = try JSONDecoder().decode(YourDecodedObject.self, from: data)
completion(.success(true))
} catch {
print("could not decode ❌")
print(error.localizedDescription)
completion(.failure(.invalidCredentials))
}
}
}.resume()
How would I send "YourDecodedObject" back to my login view?
Solution 1:[1]
SwiftUI answer
I recommend having all of the backend stuff in one class that conforms to ObservableObject.
class ContentModel: ObservableObject {
@Published var text:String = "Hello, World!"
}
In this case, I named the class ContentModel and declared it in a file with the same name. Then you can access the data in whatever view by:
struct LoginView: View {
// Access data in your class
@EnvironmentObject var model: ContentModel
var body: some View {
Text(model.text)
}
}
Don't forget to add .environmentObject(ContentModel()) to the view you're using the data in.
@main
struct StuduWidgetsApp: App {
var body: some Scene {
WindowGroup {
LoginView()
.environmentObject(ContentModel())
}
}
}
PS: If you want to use Preview Provider, you're gonna have to add there .environmentObject(ContentModel()) too.
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
.environmentObject(ContentModel())
}
}
If you want to share data from ContentModel across multiple targets open the file with ContentModel class, access the "Inspectors Menu" (on the right in Xcode) and go to the "File Inspector" tab. Locate "Target Membership"
and tick all the targets you want your data to be used in, then apply the same approach as above.
Hope this helps! It's a complicated approach, but it's worth it.
Solution 2:[2]
I believe, you wanted to pass decodedObject or AuthenticationError objects back to func login based on success or failure.
If it is so then you need to modify your completion handler as below:
APIService.shared.login(credentials: credentials) { [unowned self](result:Result<Data?, Authentication.AuthenticationError?>) in
here, you can pass success object i.e. decodedObject in Data and AuthenticationError in error part.
You don't need to have Bool here to identify success or failure. You can just check either one for nil or data present and call completion handler as follows:
if let data = data {
do {
let decodedObject = try
JSONDecoder().decode(YourDecodedObject.self, from: data)
completion(.success(decodedObject, nil))
} catch {
print("could not decode ?")
print(error.localizedDescription)
completion(.failure(nil, .invalidCredentials))
}
}
I made both callback response parameters as nil so it won't be problem in any scenario.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | RJ168 |

