關於GCD的一些小事

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

相關文章
相關標籤/搜索