等待多个异步下载任务
我想同时下载一些文件,例如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
,因为它只允许同时运行一个下载任务。
为了扩展Abhinav的答案,你应该:
- 使用
dispatch_group_create()
创建一个组。 - 在开始每个下载任务之前调用
dispatch_group_enter(group)
。 - 在任务的完成处理程序中调用
dispatch_group_leave(group)
。 - 然后调用
dispatch_group_notify(group, queue, ^{ ... })
以排队将在所有任务完成时执行的块。
你可以在这篇文章中看到一个例子。
(顺便说一下,连续执行100个dispatch_async
并不会立即创建100个线程。系统仍然可以控制用于满足队列的线程数。但是,您的代码不会等待任何任务在它返回之前完成,也不会尝试在完成多个任务之间进行同步。)
在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. // ... }) }
下载多个文件的工作目标-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"); }); }
你应该使用dispatch_group_t
。 请参阅Apple文档以解决您的案例。