在完成块完成之前返回的函数

时间:2017-09-20 14:15:28

标签: swift jwt grand-central-dispatch completionhandler

我在使用Swifts GCD时遇到了麻烦。我有一个函数,在将下载任务添加到数组时,在实际继续下载图像之前检查以确保令牌有效。

问题是如果令牌无效,在获取新令牌之后,preloadImage代码运行得太快,而requestPreloadJWTToken完成块设置了downloadTask变量,因此它不是nil。

以下是下载任务的设置。

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

以下是正在创建的令牌请求。

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

如果有人对如何从requestPreloadJWT获取完成块以完成preforImage之前的完成块有一些了解,那将是非常棒的。谢谢!

1 个答案:

答案 0 :(得分:0)

Alrighty。所以我在发表这篇文章之后立刻想出来......当然......

反正。我只是在我的preloadImage方法中将group.leave()置于闭包中,所以它看起来像:

y

我希望这可以帮助遇到它的人!