skip to Main Content

I have a closure to retrieve a token string:

var getAccessToken = { () -> (String) in
    var token = String("")
    credentialsManager.credentials(minTTL: 60) { result in
        switch result {
        case .success(let credentials):
            token = credentials.accessToken         
        case .failure(let error):
            token = ""
        }
    }
  return token
}

When I call getAccessToken() from another function like below, it always returns empty, as it doesn’t wait for credentialsManager.credentials closure to return:

    func getUserProfile(completion: @escaping (UserProfile) -> ()) {
                                      
        let accessToken = getAccessToken()
        
        let url = URL(string: "https://asdf.com")!

        enum DataTaskError: Error {
          case invalidResponse, rateLimited, serverBusy
        }
        
        var request = URLRequest(url: url)
 
        request.addValue("Bearer (accessToken)", forHTTPHeaderField: "Authorization")
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
 
        URLSession.shared.dataTask(with: request) { (data, _, _) in
         
            guard let data = data else { return }
            
            do {
                let userProfile = try JSONDecoder().decode(UserProfile.self, from: data)
                
                DispatchQueue.main.async {
                    completion(userProfile)
                }
                
            } catch {
                print(error.localizedDescription)
            }
           
        }
        .resume()
    }

I tried using a completion handler with getAccessToken:

func getAccessToken(completion: @escaping () -> (String)) { 
   //...
   completion(token)
}

but Swift errored: Argument passed to call that takes no arguments

2

Answers


  1. You are not using DataTaskError in your function. Given that, there is no reason to use a do/catch.

    var userProfile: UserProfile {
      get async throws {
        let userProfile = try JSONDecoder().decode(
          UserProfile.self,
          from: await URLSession.shared.data(
            for: {
              var request = URLRequest(url: .init(string: "https://asdf.com")!)
              [ ("Bearer (getAccessToken())", "Authorization"),
                ("application/json", "Content-Type")
              ].forEach {
                request.addValue($0, forHTTPHeaderField: $1)
              }
              return request
            } ()
          ).0
        )
    
        return await MainActor.run { userProfile }
      }
    }
    
    Login or Signup to reply.
  2. You return the token before the credentialsManager.credentials generate the token in the first case. Second case your completion handler syntax is wrong for this scenario. Use the proper completion handler as below.

    // completion will return the token, if credentialsManager is able created the token successfully
    // in any case credentialsManager failed to generate the token it will return the underlying error
    
       func getAccessToken(completion: @escaping (Result<String,Error>) -> Void) {
            credentialsManager.credentials(minTTL: 60) { result in
                switch result {
                case .success(let credentials):
                    completion(.success(credentials.accessToken))
                case .failure(let error):
                    completion(.failure(error))
                }
            }
        }
        
        func getUserProfile(completion: @escaping (UserProfile) -> ()) {
            
            getAccessToken { result in
                switch result {
                case .success(let token):
                    // What ever you do with token
                    // here
                    
                    break
                case .failure(let error):
                    // Handle error case
                    break
                }
            }
            
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search