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
CodePudding user response:
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
}
}
}
CodePudding user response:
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 }
}
}