2017-09-20 7 views
0

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!

Répondre

0

Très bien. Donc, je l'ai compris immédiatement après avoir fait ce post ... Bien sûr ...

Quoi qu'il en soit. J'ai simplement bloqué la group.leave() l'intérieur la fermeture dans ma méthode de preloadImage il ressemble:

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!) 
    } 
} 

J'espère que cela peut aider celui qui vient à travers elle!

+1

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

+0

Merci mec. Oui, cette partie de mon code a vraiment besoin d'un refactor. Encore un peu nouveau sur le terrain: p – Mystified