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