//1、 dispatch_once_t 用法
static dispatch_once_t onceToken;
//必须保证只有一个实力,才能确保只执行一次
dispatch_once(&onceToken, ^{
//单例代码
});
//2、dispatch_queue_t
/*
一共有三种
2.1、主队列 dispatch_get_main_queue()
由于主线程只有一个,所以Main自然是串行的。所添加的task会增加到主runloop
主要进行一些更新页面的操作,由于是系统提供的所以调用dispatch_release()或者dispatch_retain()不会有任何作用,同时也不会有任何问题。*/
dispatch_queue_t mainQueue = dispatch_get_main_queue();
/*
2.2、global队列dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
第一个参数我优先级
DISPATCH_QUEUE_PRIORITY_HIGH 高
DISPATCH_QUEUE_PRIORITY_DEFAULT 默认
DISPATCH_QUEUE_PRIORITY_LOW 低
DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台
第二个参数为系统保留参数,写0即可
通过方法可以生成一个系统默认的并发队列,它无法调用dispatch_resume()和dispatch_suspend(),与main一样调用dispatch_release()或者dispatch_retain()不会有任何作用,同时也不会有任何问题。
需要注意的是,三个队列不代表三个线程,可能会有更多的线程。并发队列可以根据实际情况来自动产生合理的线程数,也可理解为dispatch队列实现了一个线程池的管理,对于程序逻辑是透明的。*/
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
/*
2.3、自定义队列
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
第一个参数为队列的id,是一个CString,第二个参数是队列的属性。
通常属性用以下两个宏
DISPATCH_QUEUE_SERIAL 串行队列
(实际上我们发现这个宏实际上是NULL)
DISPATCH_QUEUE_CONCURRENT 并行队列
通过该方法就可以生成一个自定义队列
当存在多个串行队列的时候,多个队列是并行执行的,每个串行队列会生成一个线程。
串行队列每个时刻只能执行一个任务
并行队列多个任务同时执行
最后注意:dispatch_queue_create的队列必须自己进行内存管理dispatch_release()或者dispatch_retain()
*/
dispatch_queue_t typeDefQueue = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t typeDefConQueue = dispatch_queue_create("myConQueue", DISPATCH_QUEUE_CONCURRENT);
__block BOOL aFin,bFin,cFin;
static NSTimeInterval time = 0;
time = [[NSDate new] timeIntervalSince1970];
void(^Finish)(BOOL,BOOL,BOOL)=^(BOOL a,BOOL b,BOOL c){
if (a&&b&&c) {
NSTimeInterval oldTime = time;
NSTimeInterval newTime = [[NSDate new] timeIntervalSince1970];
NSLog(@"%d",(int)(newTime-oldTime));
}
};
dispatch_async(typeDefQueue, ^{
sleep(1);
NSLog(@"1");
aFin = YES;
Finish(aFin,bFin,cFin);
});
dispatch_async(typeDefQueue, ^{
sleep(1);
NSLog(@"2");
bFin = YES;
Finish(aFin,bFin,cFin);
});
dispatch_async(typeDefQueue, ^{
sleep(1);
NSLog(@"3");
cFin = YES;
Finish(aFin,bFin,cFin);
});
/*
【等待一秒】 1
【等待一秒】 2
【等待一秒】 3 3秒
*/
dispatch_async(typeDefConQueue, ^{
sleep(1);
NSLog(@"a");
aFin = YES;
Finish(aFin,bFin,cFin);
});
dispatch_async(typeDefConQueue, ^{
sleep(1);
NSLog(@"b");
bFin = YES;
Finish(aFin,bFin,cFin);
});
dispatch_async(typeDefConQueue, ^{
sleep(1);
NSLog(@"c");
cFin = YES;
Finish(aFin,bFin,cFin);
});
/*
【等待一秒】 a 1秒
【等待一秒】b
【等待一秒】 c
*/
/*
3、dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);与
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
第一个参数是一个队列
第二个参数是一个空参数空返回值的block
dispatch_sync该方法会阻塞当前线程,知道当前追加的任务执行完毕
dispatch_async该方法不会阻塞当前线程,立即返回
实际编程经验告诉我们,尽可能避免使用dispatch_sync,嵌套使用时还容易引起程序死锁。
切记不要使用以下写法,必然死锁
dispatch_sync(dispatch_get_main_queue(), ^{
});
原因分析:这段代码会阻塞主线程,然而block有时在主线程执行,所以会造成死锁
dispatch_sync(typeDefQueue, ^{
dispatch_sync(typeDefQueue, ^{
});
});
类似于这种情况。两个sync嵌套。
问题:在并行队列里面用dispatch_async追加任务后,立刻调用dispatch_release是否可以?
答:是完全没有问题的。因为queue会被block持有,所以只有等到block执行完毕,才会释放queue。
举一反三:所有的gcd的create方法,都应该用对应的内存管理函数进行内存管理。
3.1 void dispatch_async_f(dispatch_queue_t queue,void *context,dispatch_function_t work);
与
void dispatch_sync_f(dispatch_queue_t queue,void *context,dispatch_function_t work);
第一个参数为队列
第二个参数为上下文,作为work的参数
第三个参数为返回值为空,参数为void*的函数指针(注意是函数指针)
该方法主要用于调用C函数,跟dispatch_sync/dispatch_async逻辑上一样
*/
dispatch_async_f(global, (void *)@"呵呵",workFunc);
/*
4、void
dispatch_apply(size_t iterations, dispatch_queue_t queue,
void (^block)(size_t));
dispatch_apply, 作用是把指定次数指定的block添加到queue中, 第一个参数是迭代次数,第二个是所在的队列,第三个是当前索引,dispatch_apply可以利用多核的优势,所以输出的index顺序不是一定的.但是记住apply会阻塞当前线程,所以最好不要在主线程使用该方法。
void dispatch_apply_f(size_t iterations, dispatch_queue_t queue,
void *context,void (*work)(void * datas, size_t idx));
该方法与dispatch_async_f类似,不过第三个参数的函数指针,要多一个索引
*/
dispatch_async(global, ^{
dispatch_apply(10, global, ^(size_t idx) {
NSLog(@"%zu",idx);
});
});
/*
5、const char *
dispatch_queue_get_label(dispatch_queue_t queue);
获得当前队列的标签
6、void dispatch_set_target_queue( dispatch_object_t object, dispatch_queue_t queue );
为给定的对象绑定一个目标队列
该方法有两个作用
I 设置队列的优先级
如果你想让你的自定义队列的优先级等于系统队列。
但是你无法设置系统队列的优先级,那么你就可以通过这个方法
将两个队列的优先级相等。
dispatch_queue_t serialQueue = dispatch_queue_create("myQueue",NULL);
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
dispatch_set_target_queue(serialQueue, globalQueue);
II 设置队列之前的层级
多个串行队列是并行的,用这个方法可以让多个子队列被父队列调度,可以实现让多个串行队列也是串行
*/
dispatch_queue_t myQueue1 = dispatch_queue_create("mySerial1", NULL);
dispatch_queue_t myQueue2 = dispatch_queue_create("mySerial2", NULL);
dispatch_queue_t targetSerial = dispatch_queue_create("target", NULL); //父队列
dispatch_set_target_queue(myQueue1,targetSerial);
dispatch_set_target_queue(myQueue2, targetSerial);
dispatch_async(myQueue1, ^{
sleep(1);
NSLog(@"1_1");
});
dispatch_async(myQueue2, ^{
NSLog(@"2_1");
});
dispatch_async(myQueue1, ^{
NSLog(@"1_2");
});
dispatch_async(myQueue2, ^{
sleep(1);
NSLog(@"2_2");
});
/*
7、 void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,
dispatch_block_t block);
该方法用于推迟执行block
实际上并不是按照指定时间执行block,而是指定时间把block加入到queue
对于要求非常精确地程序,并不适合用该方法
第一个参数是推迟时间 dispatch_time_t类型也可以简单的直接写NSTimeInterval
第二个参数是队列
第三个参数是要执行的块
dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);
该方法创建一个dispatch_time_t
第一个参数是表示现在的时间
第二个参数表示间隔时间
dispatch_time_t dispatch_walltime(const struct timespec *when, int64_t delta);
该方法可以将 struct timespec类型的值 转成dispatch_time_t类型的值
其是用于计算绝对时间,可以用于实现闹钟
*/
dispatch_time_t(^GetDispatchTimeByData)(NSDate*) =^(NSDate *date)
{
NSTimeInterval interval;
double second,subsecond;
struct timespec time;
dispatch_time_t milestone;
interval = [date timeIntervalSince1970];
subsecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subsecond * NSEC_PER_SEC;
milestone = dispatch_walltime(&time, 0);
return milestone;
};
dispatch_time_t dTime = dispatch_time(DISPATCH_TIME_NOW, 1000ull*NSEC_PER_MSEC);
dispatch_after(dTime, mainQueue, ^{
NSLog(@"推迟了一秒");
});
dTime = GetDispatchTimeByData([NSDate dateWithTimeIntervalSinceNow:2]);
dispatch_after(dTime, mainQueue, ^{
NSLog(@"推迟了两秒");
});
/*
void dispatch_after_f(dispatch_time_t when,dispatch_queue_t queue,
void *context,dispatch_function_t work);
该方法跟dispatch_sync_f方法类似
8、dispatch_group_t dispatch_group_create(void);
创建一个group对象
9、void dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,dispatch_block_t block);与
void dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,dispatch_block_t block);
如果你想在多个异步操作全部完成之后,进行某个特定操作,比如刷新UI。
那么你就不能轻易的像串行那样追加到后面了。
group可以很好的解决这个问题
可以通过dispatch_group_async将加入异步任务
通过dispatch_group_notify添加所有任务完成的任务
*/
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, myQueue, ^{
NSLog(@"任务1");
});
dispatch_group_async(group, myQueue, ^{
NSLog(@"任务2");
});
dispatch_group_async(group, myQueue, ^{
NSLog(@"任务3");
});
dispatch_group_notify(group, myQueue, ^{
NSLog(@"全部完成");
});