GCD确实不是什么新东西,我刚开始学iOS开发的时候,也用过皮毛。但终归不是深刻学习,以前开发的时候,遇到了一个view须要同时GET三个http的数据。若是一个一个按顺序来,实在是太浪费时间,也太敷衍了事了。以前调用SkyDrive API的时候,我就发现连续几回这样调用API,等待的时间确实有点长,网速慢的话更难以接受。我其实也能够直接使用ASIHttpRequest,可是我认为,若是每次都要从开发中学会新的东西,那么就应该大胆使用本身以前未曾用过的方法。或者经过这些对比,能够找到最好的方法,到时再固定使用也不迟。html
项目需求具体为同时加载3个列表的数据,原本GCD直接使用3个异步,的确能够完成加载的任务。不过问题是,在加载的时候我禁用了UI的响应,加载完成以后,我必须从新启用UI响应。所以,3个异步进程完成后,须要再执行一些任务。显然,直接3个异步,能够经过使用一个外部变量来计数,可是这种方法有点粗暴。因此,我查阅了GCD的资料,发现有dispatch_group_t这个东西,经过先建立一个group,等这个group完成以后能够执行对应的方法。
多线程
例子代码以下:异步
1 dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 2 dispatch_group_t group = dispatch_group_create(); 3 for(id obj in array) 4 dispatch_group_async(group, queue, ^{ 5 [self doSomethingIntensiveWith:obj]; 6 }); 7 dispatch_group_notify(group, queue, ^{ 8 [self doSomethingWith:array]; 9 }); 10 dispatch_release(group);
只要将dispatch_group_async调用对应的异步block,那么当全部异步block都执行完时就会执行dispatch_group_notify的block。整段代码结构清晰,也不须要那些多余的控制变量。不过值得注意是,在ARC下也要记得release那个group,由于它不是NSObject层的对象。async
上面是同时并行的例子,下面后有是一个控制信号量的例子。信号量,我以前也不知道是什么(不详细解释,具体问谷歌),其实本身也能够手动实现,不过若是用循环来做为阻塞是会浪费大量资源的。GCD提供了一种粒度更细的控制方法:学习
1 dispatch_semaphore_t __block sem = dispatch_semaphore_create(1); 2 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 3 4 //运行代码 5 6 dispatch_semaphore_signal(sem);
这段代码要在子线程执行,在异步时,后面的代码就会等待前面的执行完才执行。dispatch_semaphore_create(1) 是返回信号量为1的dispatch_semaphore_t,也就是同时只能有1个异步的执行。dispatch_semaphore_wait()在信号量大于0时,则执行下面的代码并将信号量-1;不然就看dispatch_time_t的timeout,若是为DISPATCH_TIME_FOREVER就会一直阻塞,DISPATCH_TIME_NOW则直接跳过。dispatch_semaphore_signal()就是将信号量+1。利用这个方法,就能够更好地控制block的异步执行。spa
以前在http://www.cnblogs.com/ipinka/archive/2012/09/03/2660924.html的多选图片是经过锁来实现的,不是太优美,应该说其方法略显老旧。学习了信号量的方法,就能够写成下面这种风骚的写法:线程
1 - (NSData *) imageData 2 { 3 NSAssert(![NSThread isMainThread], @"can't be called on the main thread due to ALAssetLibrary limitations"); 4 5 dispatch_semaphore_t __block sema = dispatch_semaphore_create(0); 6 __block NSData *returnData; 7 8 ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) 9 { 10 ALAssetRepresentation *rep = [myasset defaultRepresentation]; //获取默认的representation 11 CGImageRef iref = [rep fullResolutionImage]; //获取全尺寸的CGImage 12 UIImage *tmpImage = [UIImage imageWithCGImage:iref]; //转换成UIImage 13 14 if (iref) { 15 if ([self.fileType isEqualToString:@"jpg"]) //经过判断分别转为jpg或者png 16 returnData = UIImageJPEGRepresentation(tmpImage, 1.0); 17 else 18 returnData = UIImagePNGRepresentation(tmpImage); 19 } 20 NSLog(@"imageData Succeed"); 21 dispatch_semaphore_signal(sema); 22 }; 23 24 ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) 25 { 26 NSLog(@"imageData Failed"); 27 dispatch_semaphore_signal(sema); 28 }; 29 30 31 ALAssetsLibrary *assetslibrary = [[ALAssetsLibrary alloc] init]; 32 [assetslibrary assetForURL:self.imageReferenceURL 33 resultBlock:resultblock 34 failureBlock:failureblock]; 35 36 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 37 38 return returnData; 39 }
感受真的简洁明了,实际运行后效果与以前的毫无差别,之后就能够放心大胆地利用相似的方法来进行多线程的控制了。code