GCD

GCD是苹果公司推出的专门用于简化多线程编程的技术。在GCD中,程序员已经不再需要去关心有关线程的操作(如:线程创建、线程销毁、线程调度),而是引入了任务和队列两个核心概念。

在使用GCD处理多任务执行时,只要按照如下步骤执行即可。

在Block中定义需要执行的任务内容。
把任务添加到队列queue中。
GCD对队列中的任务,按照“先进先出”的原则,根据任务添加到队列的顺序来对队列进行处理,GCD会根据任务和队列的类型,自动在多个线程之间分配工作。

在GCD中,需要处理的事务统一使用Block封装起来,称为任务。任务有两种类型,同步任务和异步任务。通过调用不同的函数,来设置任务的类型。同时,任务编写在函数的Block参数中。
// 异步任务:执行任务时,会在另外的线程中执行,即可能会创建新的线程。
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
// 同步任务:执行任务时,会在当前的线程中执行,当前线程有可能是主线程,也有可能是子线程。
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

GCD中,队列是一个重要概念。系统提供了若干预定义的队列,其中包括可以获取应用程序的主队列(任务始终在主线程上执行,与更新UI相关的操作必须在主队列中完成)。另外,可以自由创建不同类型的队列,例如:并行队列和串行队列,队列的类型决定了任务的执行方式。GCD队列严格按照“先进先出”的原则,添加到GCD队列中的任务,始终会按照加入队列的顺序被执行。

并行队列:并行队列中的任务可以在多个线程之间分配执行,分配的原则由GCD控制,因此,并行队列中的任务,虽然执行时按照先进先出进行分配的,但由于各个任务被分配到不同的线程执行,因此其完成时间有可能不同,即:后分配的任务有可能先执行完成;并发队列一定需要和异步执行的任务(使用dispatch_async())结合起来使用才有意义。
串行队列:串行队列中的任务是按照顺序一个一个完成的,当一个任务完成后,才去执行下一个任务;因此,串行队列对应一个线程执行。
主队列:主队列也是一个串行队列,主队列中的任务都在主线程中执行。

// 获取系统定义的并行队列。一般来说,开发中通常不需要自己创建并行队列,使用系统提供的即可。
dispatch_get_global_queue(long identifier, unsigned long flags);
// 创建队列。可以创建并行队列,也可以创建串行队列。该方法常用于创建串行队列。
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
// 获取主队列
dispatch_get_main_queue(void);

在GCD中存在队列和任务两个核心概念,同时队列又分为并行队列、串行队列和主队列,任务包括异步任务和同步任务。GCD的使用方法就是把任务放到队列中执行,因而根据不同的任务类型和队列类型,就会存在6种组合。

1.异步任务+并行队列
// 把异步任务放到并行队列进行执行,异步任务会在不同的线程中执行,这是最常使用的一种组合。
-(void)viewDidLoad {
    [super viewDidLoad];
    // 获取并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 创建异步任务,并放到并行队列中执行
    dispatch_async(queue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task1:%d", i);
        }
        NSLog(@"task1-----", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task2:%d", i);
        }
        NSLog(@"task2-----", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task3:%d", i);
        }
        NSLog(@"task3-----", [NSThread currentThread]);
    });
}
2.异步任务+串行队列
// 对于异步任务放在串行队列中执行时,任务只会在一个新开的线程中,按照顺序进行执行。
-(void)viewDidLoad {
    [super viewDidLoad];
    // 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("new_queue", NULL);
    // 创建异步任务,并放到串行队列中执行
    dispatch_async(queue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task1:%d", i);
        }
        NSLog(@"task1-----", [NSThread currentThread]);
    });
    // ...
}
3.异步任务+主队列
// 把异步任务放在主队列中执行,由于主队列是一个特殊的串行队列,因此任务是串行执行的,但由于主队列对应序号为1的线程,因此,即便是异步任务,也不会再创建新的线程。
-(void)viewDidLoad {
    [super viewDidLoad];
    // 获取主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    // 创建异步任务,并放到主队列中执行
    dispatch_async(mainQueue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task1:%d", i);
        }
        NSLog(@"task1-----", [NSThread currentThread]);
    });
    // ...
}
4.同步任务+并行队列
同步任务的执行是在当前线程中完成的,因此,即便是把同步任务放在并行队列中执行,由于只有1个线程,任务也是一个一个按顺序执行(串行执行)的。
-(void)viewDidLoad {
    [super viewDidLoad];
    // 获取并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PTIORITY_DEFAULT, 0);
    // 创建同步任务,并放到并行队列中执行
    dispatch_sync(mainQueue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task1:%d", i);
        }
        NSLog(@"task1-----", [NSThread currentThread]);
    });
    // ...
}
5.同步任务+串行队列
同步任务放在串行队列中执行,任务会在当前线程依次执行。
-(void)viewDidLoad {
    [super viewDidLoad];
    // 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("new_queue", NULL);
    // 创建同步任务,并放到串行队列中执行
    dispatch_sync(queue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task1:%d", i);
        }
        NSLog(@"task1-----", [NSThread currentThread]);
    });
    // ...
}
6.同步任务+主队列
这种情况下,主线程会被阻塞,程序会挂死,不能使用。
-(void)viewDidLoad {
    [super viewDidLoad];
    // 获取主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    // 同步任务,并放到主队列中执行
    dispatch_sync(mainQueue, ^{
        for(int 1 = 0; i < 2; i++) {
            NSLog(@"task1:%d", i);
        }
        NSLog(@"task1-----", [NSThread currentThread]);
    });
    // ...
}

3 线程间通信

在涉及网络数据获取的过程中,一般会使用异步任务+并发队列进行数据获取。在并行队列中的任务还可以嵌套子任务,嵌套的子任务可以设置为在主线程中执行的任务。

// 示例
-(IBAction)downLoadImageView:(id)sender {
    // 获取并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"task2-----", [NSThread currentThread]);    
    // 异步任务
    dispatch_async(queue, ^{
        // ...todo
        
        // 返回主线程 执行...
        dispatch_async(dispatch_get_main_queue(), ^{
    
        });        
    });
}

4 队列组dispatch group

在串行队列中,任务是按照进入队列的顺序依次执行,因此任务和任务之间是有明确的先后顺序的。但是对于并行队列的任务来说,由于任务会被自动分配到不同的线程中执行,因此任务完成的顺序是不确定的。假如希望给并行队列中的任务设置执行顺序,例如,当任务A和任务B完成后,再去完成任务C,就需要使用到任务组dispatch group。

// 创建队列组
dispatch_group_t dispatch_group_create(void);
// 向队列组中插入一个异步任务。
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
// 队列组中其他任务执行完成后,执行的任务,通常可以用来设置UI界面。
void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

// 示例
-(IBAction)startTask:(id)sender {
    // 创建队列组
    dispatch_group_t group = dispatch_group_create();
    // 获取并行队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    NSLog(@"task2-----", [NSThread currentThread]);    

    // 创建队列组中的第一个异步任务
    dispatch_group_async(group, queue, ^{
        // ...
        // 返回主线程 执行...
        dispatch_async(dispatch_get_main_queue(), ^{
    
        });        
    });
     // 创建队列组中的第二个异步任务
    dispatch_group_async(group, queue, ^{
        // ...
        // 返回主线程 执行...
        dispatch_async(dispatch_get_main_queue(), ^{
    
        });        
    });
    // 任务组中的任务完成后,执行的动作
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // ...
    })
}

5 延迟执行操作

有时会希望把一些操作封装起来延迟一段时间后再执行。iOS开发中,有两种常用的方法可以实现延迟执行:一种是使用GCD;另外一种是使用NSRunLoop类中提供的方法。

// 在GCD中可以使用dispatch_after()函数,封装一段代码到Block中,在设置的延迟时间dispatch_time_t之后执行。
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
// 在NSRunLoop类中,也提供了有关延迟执行的方法。由于这些方法是对NSObject类的扩展,因此,所有的类都可以使用。
@interface NSObject (NSDelayedForming)
-(void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inMode:(NSArray *)modes;
-(void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
@end

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值