skip to Main Content

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?

2

Answers


  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"

    enter image description here

    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.

    Login or Signup to reply.
  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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search