在完成块完成之前返回的函数
Posted
技术标签:
【中文标题】在完成块完成之前返回的函数【英文标题】:Functions returning before completion block finished 【发布时间】:2017-09-20 14:15:28 【问题描述】:我在使用 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 获取完成块以在 preloadImage 之前完成有所了解,那就太棒了。谢谢!
【问题讨论】:
【参考方案1】:好的。所以我在发完这篇文章后立即想通了……当然……
无论如何。我只是将 group.leave() inside 卡在我的 preloadImage 方法中,所以它看起来像:
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!)
我希望这可以帮助遇到它的人!
【讨论】:
正在研究我对此的回答。我是否建议也重构您的代码,因为您在每个完成块中都做了几乎相同的事情,所以将所有这些放在一个函数中可能会很有用。 谢谢老兄。是的,我的这部分代码肯定需要重构。对这个领域还是有点陌生:p以上是关于在完成块完成之前返回的函数的主要内容,如果未能解决你的问题,请参考以下文章