我在使用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之前的完成块有一些了解,那将是非常棒的。谢谢!
答案 0 :(得分:0)
Alrighty。所以我在发表这篇文章之后立刻想出来......当然......
反正。我只是在我的preloadImage方法中将group.leave()置于闭包中,所以它看起来像:
y
我希望这可以帮助遇到它的人!