Je rencontre des difficultés pour utiliser Swifts GCD. J'ai une fonction qui vérifie pour s'assurer qu'un jeton est valide avant de passer à télécharger l'image elle-même tout en ajoutant la tâche de téléchargement à un tableau. Le problème est que si le jeton est invalide, après être allé en chercher un nouveau, le code preloadImage s'exécute trop rapidement pour que le bloc d'achèvement requestPreloadJWTToken définisse la variable downloadTask afin qu'elle ne soit pas nulle.Fonctions renvoyées avant la fin du bloc d'achèvement
Voici la configuration de la tâche de téléchargement.
static func preloadImage(sku: String) {
// If the token exists AND is VALID (not expired) - Get the image.
let group = DispatchGroup()
var downloadTask : RetrieveImageDownloadTask? = nil
if ImageManager.tokenExists() && ImageManager.tokenIsNotExpired(){
let imageURL = ImageManager.URLBuilder(sku: sku)
// Create the request and add the token string to the authorization header
var urlRequest = try! URLRequest(url: URL(string: imageURL)!)
urlRequest.setValue("Bearer \(ImageManager.getTokenString()!)", forHTTPHeaderField: "Authorization")
downloadTask = NetRequest.downloadImage(urlRequest: urlRequest, sku: sku)
}
// Else if the token exists AND is INVALID (expired) - Delete the old token, get a new one, and fetch the image
else if ImageManager.tokenExists() && !ImageManager.tokenIsNotExpired(){
print("Token expired... Getting new token.")
_ = ImageManager.deleteToken()
if let tokenRequest = NetRequest.newTokenRequest(url: "http://\(UrlHelper.buildUrlFrom(SettingsManager.serverURL)){
group.enter()
tokenRequest.requestPreloadJWTToken(){
let imageURL = ImageManager.URLBuilder(sku: sku)
// Create the request and add the token string to the authorization header
var urlRequest = try! URLRequest(url: URL(string: imageURL)!)
urlRequest.setValue("Bearer \(ImageManager.getTokenString()!)", forHTTPHeaderField: "Authorization")
print("Token renewed. Fetching image...")
downloadTask = NetRequest.downloadImage(urlRequest: urlRequest, sku: sku)
}
group.leave()
}
}
// If the token doesn't exist, request a new one and fetch the image.
else{
print("Requesting new token...")
if let tokenRequest = NetRequest.newTokenRequest(url: "http://\(UrlHelper.buildUrlFrom(SettingsManager.serverURL)){
group.enter()
tokenRequest.requestPreloadJWTToken() {
print("Token aquired. Fetching image...")
let imageURL = ImageManager.URLBuilder(sku: sku)
// Create the request and add the token string to the authorization header
var urlRequest = try! URLRequest(url: URL(string: imageURL)!)
urlRequest.setValue("Bearer \(ImageManager.getTokenString()!)", forHTTPHeaderField: "Authorization")
downloadTask = NetRequest.downloadImage(urlRequest: urlRequest, sku: sku)
}
group.leave()
}
}
// This should always happen
group.notify(queue: DispatchQueue.main) {
MainController.imageDownloadTasks.append(downloadTask!)
}
}
Voici la requête de jeton en cours de création.
func requestPreloadJWTToken(completionHandler: @escaping() -> (/*RetrieveImageDownloadTask*/))
{
// Get the server name, username, and password
let username = SettingsManager.username
let password = SettingsManager.password
let queue = DispatchQueue(label: "Token-Request", qos: .utility, attributes: [.concurrent])
// Get download directory
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory, in: .userDomainMask)
// Create the header to be used - Add username and password
self.makeURLRequest()
self.addPreAuthentication(username, password)
// Make the request for the token
Alamofire.download("\(UrlHelper.buildUrlFrom(SettingsManager.serverURL)), method: .post, parameters: nil, headers: self.request.allHTTPHeaderFields, to: destination)
// Alamofires built in authentication will provide credentials when challenged for authentication
.authenticate(user: username, password: password)
.responseString(
queue: queue,
completionHandler: { response in
DispatchQueue.main.async {
switch response.result {
// If the result was successful, the token string is saved to a file
case .success:
// Uncomment to see token string value
//debugPrint("Value \(response.value!)")
completionHandler()
case .failure(let error):
debugPrint("Failed \(error)")
}
}
}
)
}
Si quelqu'un a une idée sur la façon dont je peux obtenir le bloc d'achèvement de requestPreloadJWT à remplir avant la preloadImage ce serait génial. Merci!
travaillait juste sur ma réponse à cela. Je pourrais aussi suggérer de refactoriser votre code puisque vous faites des choses presque identiques dans chacun de vos blocs d'achèvement, donc il pourrait être utile de mettre tout cela dans une seule fonction. – NSGangster
Merci mec. Oui, cette partie de mon code a vraiment besoin d'un refactor. Encore un peu nouveau sur le terrain: p – Mystified