iOS開發中如何使用GCD實現調度隊列組的多線程開發,假設有一個音樂應用,如果要執行多個下載歌曲的任務,這些耗時的任務會被放到多個線程上異步執行,直到全部的歌曲下載完成,彈出一個提示框來通知用戶歌曲已下載完成。
針對這個應用場景,可以考慮使用隊列組。一個隊列組可以將多個block組成一組,用於監聽這一組任務是否全部完成,指導關聯的任務全部完成後再發出通知以執行其他的操作。iOS提供瞭如下的函數開始用隊列組。
(1)創建隊列組
要想使用隊列組,首先需要創建一個隊列組對象,可以通過dispatch_group_create()函數來創建,它的定義格式如下:
dispatch_group_t dispatch_group_create(void);
在上述格式中,該函數無需傳入任何參數,其返回值是dispatch_group_t類型的。
(2)調用隊列組
創建瞭dispatch_group_t對象後,可以使用dispatch_group_async()函數將block提交至一個隊列,同時將這些block添加到一個組裡面,函數格式如下:
void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
在上述格式中,該函數沒有返回值,它需要傳入3個參數,第1個參數是創建的隊列組,第2個參數是將要添加到的隊列,第3個參數是將要執行的代碼塊。需要註意的是,該函數的名稱有一個async標志,表示這個組會異步地執行這些代碼塊。
(3)通知
當全部的任務執行完成後,通知執行其他的操作,通過dispatch_group_notify()函數來通知,它的定義格式如下:
void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
在上述定義格式中,該函數需要傳入3個參數,第1個參數表示創建的隊列組,第2個參數表示其他任務要添加到的隊列,第3個參數表示要執行的其他代碼塊。
接下來通過模擬一個需求來展示調度隊列組,就是從網上加載兩張圖片,進行組合後,最終顯示到一個ImageView上。根據這個需求,通過代碼完成相應的邏輯,具體步驟如下:
(1)新建一個SingleViewApplication工程,命名為08-Dispatch Group;
(2)進入Main.StoryBoard,從對象庫中拖拽一個ImageView到程序界面,用於顯示組合後的圖片;
(3)通過拖拽的方式,將ImageView在viewController.m文件的類擴展中進行屬性的聲明;
(4)單擊屏幕,依次從網絡上加載兩張圖片,直到這兩張圖片下載完成,將這兩張圖片進行組合,最終回到主線程上顯示,代碼如下:
#import "ViewController.h" //宏定義全局並發隊列 #define global_queue dispatch_get_global_queue(0,0) //宏定義主隊列 #define main_queue dispatch_get_main_queue() @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ViewController -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self groupImage]; } /** *使用隊列組組合圖片 */ dispatch_group_t dispatch_group_create(void); void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block); -(void)groupImage { //1、創建一個隊列組和隊列 dispatch_group_t group=dispatch_group_create(); //2、下載第1張圖片 __block UIImage *image1=nil;//定義瞭__block修飾的一個屬性,能在block中修改變量 dispatch_group_async(group, global_queue,^{ image1=[self downloadImage:@"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=4133347000,1310938944&fm=27&gp=0.jpg"]; }); //3、下載第2張圖片 __block UIImage *image2=nil;//定義瞭__block修飾的另一個屬性,能在block中修改變量 dispatch_group_async(group, global_queue,^{ image2=[self downloadImage:@"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1322912466,2607748595&fm=27&gp=0.jpg"]; }); //4、合並圖片 dispatch_group_notify(group, global_queue, ^{ //4、1開啟一個位圖上下文 UIGraphicsBeginImageContextWithOptions(image1.size, NO, 0.0); //4、2繪制第1張圖片 CGFloat image1W=image1.size.width; CGFloat image1H=image1.size.height; [image1 drawInRect:CGRectMake(0, 0, image1W, image1H)]; //4、3繪制第2張圖片 CGFloat image2W=image2.size.width*0.3; CGFloat image2H=image2.size.height*0.3; CGFloat image2Y=image1H-image2H; [image2 drawInRect:CGRectMake(140, image2Y, image2W, image2H)]; //4、4得到上下文的圖片 UIImage *fullImage=UIGraphicsGetImageFromCurrentImageContext(); //4、5結束上下文 UIGraphicsEndImageContext(); //4、6回到主線程顯示圖片 dispatch_async(main_queue,^{ self.imageView.image=fullImage; }); }); } //封裝一個方法,隻要傳入一個URL參數,就返回一張網絡上下載的圖片 -(UIImage *)downloadImage:(NSString *)urlStr{ NSURL *imageUrl=[NSURL URLWithString:urlStr]; NSData *data=[NSData dataWithContentsOfURL:imageUrl]; return [UIImage imageWithData:data]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
運行程序,程序運行成功後,單擊模擬器屏幕,可見第1張人物圖片和第二張百度logo圖片組合在一起,形成一張圖片顯示到屏幕上,如下圖所示: