利用GCD下载大量图片的Demo
GCD简介:
http://www.dreamingwish.com/dream-2012/gcd介绍(一)-基本概念和dispatch-queue.html
http://blog.csdn.net/liuhongwei123888/article/details/6899366
GCD不需要使用锁,但是可以用 用户队列(必须用用户队列[dispatch_queue_create ],而非全局队列) 替代锁来完成同步机制。然后可以用dispatch_async 或者 dispatch_sync 将共享数据的访问代码封装起来。
- - (id)something
- {
- __block id localSomething;
- <span style="color:#ff0000;">dispatch_sync</span>(queue, ^{
- localSomething = [something retain];
- });
- return [localSomething autorelease];
- }
- - (void)setSomething:(id)newSomething
- {
- <span style="color:#ff0000;">dispatch_async</span>(queue, ^{
- if(newSomething != something)
- {
- [something release];
- something = [newSomething retain];
- [self updateSomethingCaches];
- }
- });
- }
dispatch_async 与 dispatch_get_global_queue的区别和联系:
dispatch_async:提交块对象给指定的调剂队列,异步履行。
GCD中有三种队列类型:
- The main queue:
与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。 - Global queues:
全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。 - 用户队列:
用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列) 是用函数 dispatch_queue_create
创建的队列. 这些队列是串行的。正因为如此,它们可以用来完成同步机制, 有点像传统线程中的mutex。
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [self goDoSomethingLongAndInvolved];
- NSLog(@"Done doing something long and involved");
- );
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [self goDoSomethingLongAndInvolved];
- dispatch_async(dispatch_get_main_queue(), ^{
- [textField setStringValue:@"Done doing something long and involved"];
- });
- });
dispatch_queue_create
初始化一个。然后可以用
dispatch_async
dispatch_sync
将共享数据的访问代码封装起来:
- <pre name="code" class="cpp">- (id)something
- { __block id localSomething;
- dispatch_sync(queue, ^{ localSomething = [something retain];
- });
- return [localSomething autorelease];
- }
- - (void)setSomething:(id)newSomething
- { dispatch_async(queue, ^{
- if(newSomething != something)
- {
- [something release];
- something = [newSomething retain];
- [self updateSomethingCaches];
- } });
- }</pre><br><br><br>
值得注意的是dispatch queue是非常轻量级的,就像你以前使用lock一样。
- //dispatch_get_global_queue()是全局队列,并发执行
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- for (int i=0; i<100; i++) {
- float newProgress = [progressView progress] + 0.01;
- //刷新主线程
- dispatch_async(dispatch_get_main_queue(), ^{
- progressView.progress = newProgress;
- });
- usleep(1000*100);
- } //for loop
- });//dispatch_async
有时候我们有一段代码要像这样操作一个数组,但是在操作完成后,我们还需要对操作结果进行其他操作:
- for(id obj in array)
- [self doSomethingIntensiveWith:obj];
- [self doSomethingWith:array];
这时候使用GCD的dispatch_async 就悲剧了,我们还不能简单的使用dispatch_sync来解决这个问题,因为这将导致每个迭代器阻塞,就完全破坏了平行计算。
A:用三个线程串行执行做一件事,完成之后回调finish方法。
B:把三个线程放在group里面,完成之后回调finish方法。
A和B的区别是:A三个线程是串行的而B三个线程是并行的,都是在线程完成之后回调finish的方法。
决这个问题的一种方法是使用dispatch group。一个dispatch group可以用来将多个block组成一组以监测这些Block全部完成或者等待全部完成时发出的消息使用函数dispatch_group_create来创建,然后使用函数dispatch_group_async来将block提交至一个dispatch queue,同时将它们添加至一个组。所以我们现在可以重新编码:
- dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_group_t group = dispatch_group_create();
- for(id obj in array)
- dispatch_group_async(group, queue, ^{
- [self doSomethingIntensiveWith:obj];
- });
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- dispatch_release(group);
- [self doSomethingWith:array];
-doSomethingWith:放在后台执行。我们使用dispatch_group_async函数建立一个block在组完成后执行:
- dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_group_t group = dispatch_group_create();
- for(id obj in array)
- dispatch_group_async(group, queue, ^{
- [self doSomethingIntensiveWith:obj];
- });
- dispatch_group_notify(group, queue, ^{
- [self doSomethingWith:array];
- });
- dispatch_release(group);
-doSomethingWith:需要在主线程中执行,比如操作GUI,那么我们只要将main queue而非全局队列传给dispatch_group_notify函数就行了。
对于同步执行,GCD提供了一个简化方法叫做dispatch_apply。这个函数调用单一block多次,并平行运算,然后等待所有运算结束,就像我们想要的那样
- dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_apply([array count], queue, ^(size_t index){
- [self doSomethingIntensiveWith:[array objectAtIndex:index]];
- });
- [self doSomethingWith:array];
这很棒,但是异步咋办?dispatch_apply函数可是没有异步版本的。但是我们使用的可是一个为异步而生的API啊!所以我们只要用dispatch_async函数将所有代码推到后台就行了:
- dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_async(queue, ^{
- dispatch_apply([array count], queue, ^(size_t index){
- [self doSomethingIntensiveWith:[array objectAtIndex:index]];
- });
- [self doSomethingWith:array];
- });