GCD部分用法

13 篇文章 0 订阅
4 篇文章 0 订阅

1,用gcd延迟执行任务

如果我们需要某个方法在一段时间后执行,那么我们常常会调用这样的方法

- (void)viewDidLoad{

    [super viewDidLoad];

    [self performSelector:@selector(printString:) withObject:@"Grand Central Dispatch" afterDelay:3.0];

}

- (void) printString:(NSString *)paramString{

    NSLog(@"%@", paramString);

}

但是,我们要讲的是gcd方式,那么在gcd的世界里,也有2个类似的方法来实现延迟执行的功能

dispatch_after 方法


void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);


when:所指定的时间


queue:指定的队列


block:执行的Block


Block加入指定队列,并按照指定时间执行。

先上例子:

- (void)viewDidLoad{

    [super viewDidLoad];

    

    double delayInSeconds = 2.0;

 

    // 创建延期的时间 2S,因为dispatch_time使用的时间是纳秒,尼玛,比毫秒还小,太夸张了!!!

    dispatch_time_t delayInNanoSeconds =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

    // 得到全局队列

    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 延期执行

    dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void){

        NSLog(@"Output GCD !");

        

    });

}

dispatch_time 方法


dispatch_time_t dispatch_time(dispatch_time_t when,int64_t delta);


when:指定的开始点,可以用 DISPATCH_TIME_NOW 来指定一个当前的时间点


delta:纳秒数


创建一个时间点(dispatch_time_t),返回的时间点为:delta+ when


dispatch_time_t:纯粹就是一个时间点。


dispatch_after 方法


void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);


when:时间点


queue:指定的队列


block:执行的Block


Block加入到指定的队列,并且在指定的时间点执行。



dispatch_after_f 方法


我想有了,前面知识的铺垫,这个方法理解起来,就像在切菜!!!


直接上例子:


- (void)viewDidLoad{

    [super viewDidLoad];

    

    double delayInSeconds = 2.0;

    dispatch_time_t delayInNanoSeconds =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    

    dispatch_after_f(delayInNanoSeconds,concurrentQueue, @"GCD", processSomething);

    

}


void processSomething(void *paramContext){

    

    NSLog(@"This is %@",paramContext);

}


注意:dispatch_after_f 执行的是一个纯C函数(processSomething)!



2,用gcd来实现单例模式

APP 的生命周期内你想确保每段代码只执行一次,即使它在代码的不同地方多次调用(比如单例的初始化)


直接代码:


static dispatch_once_t onceToken;

void (^executedOnlyOnce)(void) = ^{

    static NSUInteger numberOfEntries = 0;

    numberOfEntries++;

    NSLog(@"Executed %lu time(s)", (unsigned long)numberOfEntries);

};


调用:

dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);


dispatch_once(&onceToken, ^{

    dispatch_async(concurrentQueue,executedOnlyOnce);

});


dispatch_once(&onceToken, ^{

    dispatch_async(concurrentQueue,executedOnlyOnce);

});


可以发现,输出只有一行,虽然我们调用了2次。因为我们传入的dispatch_once_t是相同的。编译器只执行一次操作。


dispatch_once 方法


void dispatch_once(dispatch_once_t *predicate,dispatch_block_t block);


predicate:单例标识符

block:执行的Block


Application周期内,只执行一次Block。即:单例模式


dispatch_once_t:可以理解为单例标识符,dispatch_once方法用它来测试Block是否被执行过了。如果执行过了,那么就不在执行。



3,用gcd将任务分组

有时候,我们可能执行一系列的任务。由于彼此之间的依赖关系。比如有3个任务:ABC;我们必须执行了任务A,才能执行任务B,最后执行任务C。这样的话,我们可以用GCD的分组机制来将多个任务来按照预定的顺序来执行。


先看例子吧:


我们先来搞清楚以下的关于调度组的一些常用方法


dispatch_group_t 方法


typedef struct dispatch_group_s *dispatch_group_t;


指代一个调度组。

调度组负责监视加入到该组的多个Block。每个Block可以是异步或者同步(取决与你自己)。

调度组中的Block可以在不同的队列中执行;并且一个Block可以被添加到多个调度组中。


dispatch_group_create 方法


dispatch_group_t dispatch_group_create(void);


创建一个调度组


dispatch_group_async 方法


void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);


group:要分发到的调度组


queue:执行Block的队列


block:要执行的Block


Block分发到指定的队列(用指定的队列来执行Block),并且将该Block加入到指定的调度组中。


dispatch_group_notify 方法


void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);


当调度组中的所有Block被执行完成后,将调用被分配到指定队列的Block


理论一大堆了,还是用事实来说话:


例子:


- (void)viewDidAppear:(BOOL)animated{

    

    [super viewDidAppear:animated];

    

    dispatch_group_t taskGroup = dispatch_group_create();// 创建一个调度组

    dispatch_queue_t mainQueue = dispatch_get_main_queue();// 创建队列

    

    // 任务1

    // Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。

    dispatch_group_async(taskGroup, mainQueue, ^{

        

        [self reloadTableView];

    });

    

    // 任务2

    // Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。

    dispatch_group_async(taskGroup, mainQueue, ^{

        

        [self reloadScrollView];

    });

    

    // 任务3

    // Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。

    dispatch_group_async(taskGroup, mainQueue, ^{

        

        [self reloadImageView];

    });

    // 当指定调度组(taskGroup)中的所有Block都执行完成后,将执行给定的Block,用指定的队列(mainQueue)。

    dispatch_group_notify(taskGroup, mainQueue, ^{

        // 指定的Block

        [[[UIAlertView alloc] initWithTitle:@"Finished" message:@"All tasks are finished" delegate:nil

                          cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];

        

    });

    

    // 最后,必须release 掉调度组(taskGroup

    dispatch_release(taskGroup);

    

}


#pragma mark - 执行的多个方法


- (void) reloadTableView{

    

    NSLog(@"%s", __FUNCTION__);

}


- (void) reloadScrollView{

    

    NSLog(@"%s", __FUNCTION__);

}


- (void) reloadImageView{

    

    NSLog(@"%s", __FUNCTION__);

    

}


可见,执行顺序,跟加入到调度组中的次序是一样的。


等等,有点疑惑是不是?!

我对每个任务用的是方法dispatch_group_async,是异步的啊。为什么顺序却不变呢?!

呵呵,基础不扎实啊!因为他们都是分配给同一个队列dispatch_get_main_queue() 中的!在一个队列中是串行的啊。所以,还是按照顺序来。


对,在GCD中,每个方法往往都有两种,一种是执行标准Block,一种是执行C函数的。


那么,就ok,我们来看看执行C函数的写法:


例子:


- (void)viewDidAppear:(BOOL)animated{

    

    [super viewDidAppear:animated];

    

    dispatch_group_t taskGroup = dispatch_group_create();

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_group_async_f(taskGroup, mainQueue,(void *)self, reloadAllComponents);

    

    dispatch_group_notify(taskGroup, mainQueue, ^{

        

        [[[UIAlertView alloc] initWithTitle:@"Finished"

                                    message:@"All Tasks are Finished"

                                   delegate:nil

                          cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];

    });

    

    dispatch_release(taskGroup);

    

}


// 定义调度组要执行的C函数

void reloadAllComponents(void *context){

    MoreViewController *self =(MoreViewController *)context;

    [self reloadTableView];

    [self reloadScrollView];

    [self reloadImageView];

}

注意:

因为dispatch_group_async_f不像dispatch_group_t那样使用Block,可以访问当前类的变量。


由于 dispatch_group_async_f 接受 C 函数作为一个代码块来执行,所以,我们要执行reloadTableView方法,reloadScrollView方法,reloadImageView方法,必须有个当前类的引用!!!!!

那么 C 函数必须有一 个引用到 Self,这个 Self 能够调用当前对象的实例方法


4,用gcd创建自己的分发队列

当然,GCD也给予了我们很多自主性质的操作。就是可以定义我们自己的分发队列。

有时候,突发奇想,自己定义一个队列,做自己的事情!那该多自由!这一定可以有的,哟,亲!!

爽啊!!!

注意:我们自定义的队列,往往不会在主队列中执行。而是单独分配一个线程来维护我们所定义的队列。


先来看代码吧:


- (void)viewDidAppear:(BOOL)animated{

    

    [super viewDidAppear:animated];

    

    // 创建指定的自定义的串行队列

    dispatch_queue_t firstSerialQueue = dispatch_queue_create("com.pixolity.GCD.serialQueue1", NULL);

    

    // 让队列异步执行Block

    dispatch_async(firstSerialQueue, ^{

        NSUInteger counter = 0;

        for (counter = 0; counter < 5; counter++){

            NSLog(@"First iteration, counter = %lu", (unsigned long)counter); }

        NSLog(@"Current thread = %@", [NSThread currentThread]);

    });

    

    dispatch_async(firstSerialQueue, ^{

        NSUInteger counter = 0; for (counter = 0;counter < 5;counter++){

            NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);

            NSLog(@"Current thread = %@", [NSThread currentThread]);

        }

    });

    

    dispatch_async(firstSerialQueue, ^{ NSUInteger counter = 0;

        for (counter = 0;counter < 5;counter++){

            NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);

            NSLog(@"Current thread = %@", [NSThread currentThread]);

        }

    });

    // 销毁队列

    dispatch_release(firstSerialQueue);

    

    // 输出主队列,比较会发现,我们自定义的队列,并不在主线程上,效率还是蛮高的。

    dispatch_queue_t mainQueue1 = dispatch_get_main_queue();

    dispatch_async(mainQueue1, ^(void) {

        NSLog(@"Main thread = %@", [NSThread mainThread]);

    });

}


上面是Block形式的。还有一个C函数的自定义


// 定义任务1-C函数形式

void firstIteration(void *paramContext){

    NSUInteger counter = 0;

    for (counter = 0;counter < 5;counter++){

        NSLog(@"First iteration, counter = %lu", (unsigned long)counter);

    }

}


// 定义任务2-C函数形式

void secondIteration(void *paramContext){

    NSUInteger counter = 0;

    for (counter = 0;counter < 5;counter++){

        NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);

    }

}


// 定义任务3-C函数形式

void thirdIteration(void *paramContext){

    NSUInteger counter = 0;

    for (counter = 0;counter < 5;counter++){

        NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);

    }

}


- (void)viewDidAppear:(BOOL)animated{

    

    [super viewDidAppear:animated];

    

    dispatch_queue_t firstSerialQueue = dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0);

    dispatch_async_f(firstSerialQueue, NULL, firstIteration);

    dispatch_async_f(firstSerialQueue, NULL, secondIteration);

    dispatch_async_f(firstSerialQueue, NULL, thirdIteration);

    dispatch_release(firstSerialQueue);

}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值