小引:有时候,我们在开发iOS程序时,需要批量下载一些文件(比如图片),只有当全部文件下载完毕,我们才做相应的处理(界面更新,通知用户等)——也就是说虽然有多个文件在下载,但是我们只需要收到一个全部下载完毕的通知。
在网上搜索了一番,感觉使用GCD的高级功能Group,比较方便。下面写了一个小Demo,实现了多个图片文件的异步并发下载,缓存到本地,并显示到界面中。
参考了唐巧的一篇博文:使用GCD。
另外感兴趣的同学可以看看下面几篇GCD相关文章,非常不错:
raywenderlich:Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial
苹果官网:Grand Central Dispatch (GCD) Reference 和 Concurrency Programming Guide
Demo可以到Github上下载:
https://github.com/BeyondVincent/DownloadImage_GCD
下面是使用GCD Group的关键代码:
- (IBAction)downloadAction:(UIButton *)sender { [self resetImage]; self.status.text = @"正在下载"; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t downloadImage = dispatch_group_create(); for (ImageInfo *info in self.imageList) { NSString* imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:info.imageName]; NSFileManager *fileManager = [NSFileManager defaultManager]; // 如果本地不存在图片,则从网络中下载 if (![fileManager fileExistsAtPath:imagePath]) { dispatch_group_async(downloadImage, queue, ^{ NSLog(@"Starting image download:%@", imagePath); // URL组装和编码 NSString *urlString = [NSString stringWithFormat:@"%@/%@", self.baseUrl, info.imageName]; NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; NSLog(@"image download from url:%@", urlString); // 开始下载图片 NSData *responseData = [NSData dataWithContentsOfURL:url]; // 将图片保存到指定路径中 [responseData writeToFile:imagePath atomically:YES]; // 将下载的图片赋值给info info.image = [UIImage imageWithData:responseData]; NSLog(@"image download finish:%@", imagePath); }); } else { // 将本地图片加载到systemInfo.MyImage info.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath]]; } } dispatch_group_notify(downloadImage, dispatch_get_main_queue(), ^{ // 图片加载完毕之后,显示出来 self.status.text = @"图片文件下载并缓存完毕"; [self showImage]; }); }
上面关键的代码是dispatch_group_async(并行执行线程1)和dispatch_group_notify(全部下载完毕,由此进行回调通知)。在for语句中循环开启了6个并发任务。当6个任务完成之后,调用showImage方法,将图片显示出来。
下面是运行效果图(第一个图为程序刚刚启动时的效果,第二个为点击开始异步下载图片按钮之后的效果):
QQ20130502-3
QQ20130502-2
在写本Demo的时候,遇到了以下两个问题
- 关于图片的加载,UIImage中的imageNamed:方法只能加载程序main bundle中的图片。要想加载Document中的图片,需要使用UIImage的imageWithData方法。更多相关资料可以阅读苹果官方介绍:UIImage
- NSURL URLWithString:myString returns Nil。在初始化NSURL实例对象是,一直都返回Nil。后来在这里(Here)发现原来是URL中含有特殊字符,需要进行编码处理,照着链接中的方法搞定。
_________________
本文由破船原创
转载请注明出处:BeyondVincent的博客
_________________