2025-05-25

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圖片組合在一起,形成一張圖片顯示到屏幕上,如下圖所示:

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *