我想同时下载一些文件,例如100个文件。所以我决定将我的下载线程添加到一个调度队列,GCD将调整同时运行的线程数。
这里的问题是:dispatch_async
中的块将立即完成,因为task
将在另一个线程上运行。因此,如果urls
的长度为100,则会立即创建100个线程。
var queueDownloadTask = dispatch_queue_create("downloadQueue", nil)
for url in urls {
dispatch_async(queueDownloadTask) {
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let fileTransferSession = NSURLSession(configuration: config)
let task = fileTransferSession.downloadTaskWithURL(url, completionHandler: { (responseUrl, response, error) -> Void in
println("completed")
})
task.resume()
}
}
如何在dispatch_async
中配置块以等待下载任务完成?我不想使用dispatch_semaphore
,因为它只允许运行一次下载同时完成任务。
答案 0 :(得分:29)
在Swift3中,
func executeMultiTask() {
//1. Create group
let taskGroup = DispatchGroup()
//2. Enter group
taskGroup.enter()
myTask1.execute(completeHandler: {
// ...
//3. Leave group
taskGroup.leave() //< balance with taskGroup.enter()
})
/* Add more tasks ...
//2. Enter group
taskGroup.enter()
myTask2.execute(completeHandler: {
//3. Leave group
defer {
// Use `defer` to make sure, `leave()` calls are balanced with `enter()`.
taskGroup.leave()
}
// ... more
})
*/
//4. Notify when all task completed
taskGroup.notify(queue: DispatchQueue.main, work: DispatchWorkItem(block: {
// All tasks are done.
// ...
})
}
答案 1 :(得分:28)
要扩展Abhinav的答案,你应该:
dispatch_group_create()
创建群组。dispatch_group_enter(group)
。dispatch_group_leave(group)
。dispatch_group_notify(group, queue, ^{ ... })
以排队将在所有任务完成后执行的块。您可以在this post中看到一个示例。
(顺便说一句,连续执行100 dispatch_async
并不会立即创建100个线程。系统仍然可以控制用于满足队列的线程数。但是,您的代码确实如此。不等待任何任务在返回之前完成,也不会尝试在完成的多个任务之间进行同步。)
答案 2 :(得分:3)
下载多个文件的工作目标-c示例
- (void) downloadFiles: (NSMutableArray *) fileArray : (NSString *)destParentDir{
dispatch_group_t serviceGroup = dispatch_group_create();
for (id fileInfo in fileArray) {
dispatch_group_enter(serviceGroup);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *fileName = [fileInfo valueForKey:@"name"];
//Create SubDirs if needed, note that you need to exclude file name for the dirsString :)
//[fileManager createDirectoryAtPath:dirsString withIntermediateDirectories:true attributes:nil error:NULL];
//Download file
NSURL *url = [NSURL URLWithString:@"YOUR_FILE_URL"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if(urlData)
{
NSString *localPath = [NSString stringWithFormat:@"%@/%@", destParentDir, fileName];
[urlData writeToFile:localPath atomically:YES];
}
dispatch_group_leave(serviceGroup);
}
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(),^{
NSLog(@"Complete files download");
});
}
答案 3 :(得分:2)
您应该使用dispatch_group_t
。请参阅Apple documentation以解决您的问题。
答案 4 :(得分:0)
创建一个 DispatchGroup
。将每次下载都包装在 enter
和 leave
中。提供对 notify
的回调,当所有配对完成后将调用该回调。
var dispatchGroup = DispatchGroup()
for url in urls {
// ... Set up the download
dispatchGroup.enter()
let task = fileTransferSession.downloadTaskWithURL(url) { (responseUrl, response, error) -> Void in
println("Individual download complete.")
dispatchGroup.leave()
})
task.resume()
dispatchGroup.notify(queue: .main) {
println("All downloads complete.")
}
}