本文主要是介绍GCD部分用法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
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个任务:A、B、C;我们必须执行了任务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);
}
这篇关于GCD部分用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!