Jim*_*alo 7 multithreading grand-central-dispatch ios swift
我正在尝试使用宏中央调度等待文件完成下载后再继续.这个问题是从这个问题衍生出来的:Swift(iOS),等待所有图像在返回之前完成下载.
我只是试图找出如何让dispatch_group_wait(或类似)实际等待,而不是在下载完成之前继续.请注意,如果我使用NSThread.sleepForTimeInterval而不是调用downloadImage,它等待就好了.
我错过了什么?
class ImageDownloader {
var updateResult = AdUpdateResult()
private let fileManager = NSFileManager.defaultManager()
private let imageDirectoryURL = NSURL(fileURLWithPath: Settings.adDirectory, isDirectory: true)
private let group = dispatch_group_create()
private let downloadQueue = dispatch_queue_create("com.acme.downloader", DISPATCH_QUEUE_SERIAL)
func downloadImages(imageFilesOnServer: [AdFileInfo]) {
dispatch_group_async(group, downloadQueue) {
for serverFile in imageFilesOnServer {
print("Start downloading \(serverFile.fileName)")
//NSThread.sleepForTimeInterval(3) // Using a sleep instead of calling downloadImage makes the dispatch_group_wait below work
self.downloadImage(serverFile)
}
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // This does not wait for downloads to finish. Why?
print("All Done!") // It gets here too early!
}
private func downloadImage(serverFile: AdFileInfo) {
let destinationPath = imageDirectoryURL.URLByAppendingPathComponent(serverFile.fileName)
Alamofire.download(.GET, serverFile.imageUrl) { temporaryURL, response in return destinationPath }
.response { _, _, _, error in
if let error = error {
print("Error downloading \(serverFile.fileName): \(error)")
} else {
self.updateResult.filesDownloaded++
print("Done downloading \(serverFile.fileName)")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:这些下载是对HTTP POST请求的响应,我使用的是不支持异步操作的HTTP服务器(Swifter),因此我需要等待完整下载完成才能返回响应(请参阅原始问题引用上面有更多细节).
Rob*_*Rob 11
当dispatch_group_async用于调用本身异步的方法时,只要所有异步任务都已启动,该组就会完成,但不会等待它们完成.相反,您可以dispatch_group_enter在进行异步调用之前手动调用,然后dispatch_group_leave在异步调用完成时调用.然后dispatch_group_wait现在将按预期运行.
但是,要实现此目的,首先要更改downloadImage为包含完成处理程序参数:
private func downloadImage(serverFile: AdFileInfo, completionHandler: (NSError?)->()) {
let destinationPath = imageDirectoryURL.URLByAppendingPathComponent(serverFile.fileName)
Alamofire.download(.GET, serverFile.imageUrl) { temporaryURL, response in return destinationPath }
.response { _, _, _, error in
if let error = error {
print("Error downloading \(serverFile.fileName): \(error)")
} else {
print("Done downloading \(serverFile.fileName)")
}
completionHandler(error)
}
}
Run Code Online (Sandbox Code Playgroud)
我已经做了一个传递错误代码的完成处理程序.根据你的需要调整,但希望它能说明这个想法.
但是,提供完成处理程序后,现在,当您执行下载时,您可以创建一个组,在启动每次下载之前"输入"该组,在异步调用完成处理程序时"离开"该组.
但dispatch_group_wait如果你不小心可以死锁,如果从主线程完成,可以阻止UI等等.更好的是,你可以dispatch_group_notify用来实现所需的行为.
func downloadImages(_ imageFilesOnServer: [AdFileInfo], completionHandler: @escaping (Int) -> ()) {
let group = DispatchGroup()
var downloaded = 0
group.notify(queue: .main) {
completionHandler(downloaded)
}
for serverFile in imageFilesOnServer {
group.enter()
print("Start downloading \(serverFile.fileName)")
downloadImage(serverFile) { error in
defer { group.leave() }
if error == nil {
downloaded += 1
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
你会这样称呼它:
downloadImages(arrayOfAdFileInfo) { downloaded in
// initiate whatever you want when the downloads are done
print("All Done! \(downloaded) downloaded successfully.")
}
// but don't do anything contingent upon the downloading of the images here
Run Code Online (Sandbox Code Playgroud)
对于Swift 2和Alamofire 3的答案,请参阅此答案的上一版本.
在Swift 3 ......
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
// do something, including background threads
dispatchGroup.leave()
dispatchGroup.notify(queue: DispatchQueue.main) {
// completion code
}
Run Code Online (Sandbox Code Playgroud)
https://developer.apple.com/reference/dispatch/dispatchgroup
| 归档时间: |
|
| 查看次数: |
7405 次 |
| 最近记录: |