ios之GCD学习笔记(1)
来源:互联网 发布:郎咸平小三 知乎 编辑:程序博客网 时间:2024/04/28 15:10
//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(@"全部完成"); });
- ios之GCD学习笔记(1)
- ios之GCD学习笔记(2)
- ios之GCD学习笔记(3)
- iOS学习笔记之GCD详解
- iOS学习笔记之GCD详解
- iOS 学习 之 gcd
- iOS并发编程(GCD)学习笔记
- iOS并发编程(GCD)学习笔记
- iOS并发编程(GCD)学习笔记
- iOS GCD 学习笔记(一)
- 学习笔记之GCD
- IOS学习笔记51--多线程编程之GCD
- iOS多线程学习之GCD
- iOS 多线程学习之GCD
- iOS多线程之GCD学习
- iOS-GCD学习之Group
- iOS 之 GCD(1)
- iOS学习笔记1-多线程GCD与block
- nodejs 读写文件
- 指尖上的电商---(5)schema.xml配置详解
- Spring MVC @Transactional注解方式事务失效的解决办法
- View not attached to window manager
- [SCU 4514] Simple dp (XJBLG法)
- ios之GCD学习笔记(1)
- STL快速入门
- TortoiseSVN中分支和合并实践
- Greendao的使用
- JAVA多线程(二)竞态条件、死锁及同步机制
- windows下免安装版的mysql的正确安装,折腾出来的方法
- 一种通过自动脚本抓取Android 手机log的方法
- ios之GCD学习笔记(2)
- Mysql 5.7 information_schema 的status和variables表deprecated