专栏首页ios技术安装GCD梳理与总结-常用API操练
原创

GCD梳理与总结-常用API操练

  • 延时执行(dispatch_after) 需要注意的是:dispatch_after函数并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到队列中。严格来说,这个时间并不是绝对准确的,但想要大致延迟执行任务,dispatch_after函数是很有效。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{     // 2秒后异步追加任务代码到主队列     NSLog(@"----执行任务---当前线程%@",[NSThread currentThread]); });复制代码
  • 只执行一次(dispatch_once) 通常在创建单例时使用,多线程环境下也能保证线程安全

static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{     NSLog(@"----只执行一次的任务---当前线程%@",[NSThread currentThread]); });复制代码
  • 重复执行(dispatch_apply) 快速遍历方法,可以替代for循环的函数。dispatch_apply按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。你可以把他理解成for循环遍历,其优势是可以充分利用多核的性能。

//并发队列 dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   //串行队列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue",   DISPATCH_QUEUE_SERIAL); //你可以试试并发和串行的区别 dispatch_apply(10, globalQueue, ^(size_t index) {     NSLog(@"执行第%zd次的任务,%@",index,[NSThread currentThread]);     [NSThread sleepForTimeInterval:1]; });复制代码
  • 队列组(dispatch_group) 比如当我们遇到需要异步下载3张图片,都下载完之后再拼接成一个整图的时候,就需要用到gcd队列组。 dispatch_group_enter 标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1 dispatch_group_leave 标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。 当 group 中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,以及执行追加到dispatch_group_notify中的任务。

//创建队列组 dispatch_group_t group = dispatch_group_create(); //全局串行队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  dispatch_group_enter(group); dispatch_async(queue, ^{     // 第一个任务     [NSThread sleepForTimeInterval:2];     NSLog(@"执行第一个任务");     dispatch_group_leave(group); });  dispatch_group_enter(group); dispatch_async(queue, ^{     // 第二个任务     [NSThread sleepForTimeInterval:2];     NSLog(@"执行第二个任务");     dispatch_group_leave(group); });  dispatch_group_notify(group, dispatch_get_main_queue(), ^{     [NSThread sleepForTimeInterval:2];     NSLog(@"执行最后的汇总任务"); }); 复制代码
  • 信号量(dispatch_semaphore) 用来设置当前队列的最大并发数。 信号量就3个方法,1创建信号数量,2wait,3signal。信号量就类似交通信号灯。 dispatch_semaphore_wait判读当前信号量。为0则红灯禁止通行,等待信号量大于0后放行。放行后对信号量-1; dispatch_semaphore_signal与wait成对出现。表示任务已结束。对信号量+1;

//创建信号量为2 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); //全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  //任务1 dispatch_async(queue, ^{     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);     NSLog(@"----开始执行第一个任务---");     [NSThread sleepForTimeInterval:2];     NSLog(@"----结束执行第一个任务---",);      dispatch_semaphore_signal(semaphore); });  //任务2 dispatch_async(queue, ^{     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);     NSLog(@"----开始执行第二个任务---");     [NSThread sleepForTimeInterval:1];     NSLog(@"----结束执行第二个任务---");     dispatch_semaphore_signal(semaphore); });  //任务3 dispatch_async(queue, ^{     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);     NSLog(@"----开始执行第三个任务---",);     [NSThread sleepForTimeInterval:2];     NSLog(@"----结束执行第三个任务---");     dispatch_semaphore_signal(semaphore); });复制代码
  • 栅栏(dispatch_barrier) 在栅栏前放入队列的操作执行完后,再执行栅栏后放入队列的操作。当然也可以用Dispatch Group实现相同功能,只是比较而言,dispatch_barrier_async会更加顺滑。需要注意的是:使用的队列应该是你自己创建的并发队列。不可以是系统队列或者串行队列,具体原因,读者可以思考一下。

//全局并发队列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_CONCURRENT);  dispatch_async(queue, ^{     [NSThread sleepForTimeInterval:3];     NSLog(@"栅栏前的任务"); }); dispatch_async(queue, ^{     [NSThread sleepForTimeInterval:1];     NSLog(@"栅栏前的任务"); });  //栅栏 dispatch_barrier_async(queue, ^{     // 等待处理     [NSThread sleepForTimeInterval:2];     NSLog(@"-栅栏等待-"); });  dispatch_async(queue, ^{     [NSThread sleepForTimeInterval:2];     NSLog(@"栅栏后的任务"); }); dispatch_async(queue, ^{     [NSThread sleepForTimeInterval:2];     NSLog(@"栅栏后的任务"); });复制代码
  • 挂起(dispatch_suspend)、恢复(dispatch_resume)队列 简单来说,就是可以暂停、恢复队列上的任务。但是这里的“挂起”,并不能保证可以立即停止队列上正在运行的任务,也就是如果挂起之前已经有队列中的任务在进行中,那么该任务依然会被执行完毕

//串行队列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_SERIAL);  dispatch_async(queue, ^{     // 执行第一个任务     NSLog(@"----执行第一个任务---"); });  dispatch_async(queue, ^{     // 执行第二个任务     NSLog(@"开始执行第二个任务");     [NSThread sleepForTimeInterval:5];     NSLog(@"结束执行第二个任务"); });  dispatch_async(queue, ^{     // 执行第三个任务     NSLog(@"开始执行第三个任务");     [NSThread sleepForTimeInterval:5];     NSLog(@"结束执行第三个任务"); });  //此时发现意外情况,挂起队列 NSLog(@"suspend"); dispatch_suspend(queue);  //挂起3秒之后,恢复正常 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{     //恢复队列     NSLog(@"3秒后恢复resume");     dispatch_resume(queue); });复制代码

定时器 GCD的定时器比NSTimer有更高的进度,而且避免了NSTimer的三大缺陷(RunLoop,不能跨越线程操作,内存泄漏风险)

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建定时器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//构建参数。设置从何时开始/设置时间间隔
dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, 0* NSEC_PER_SEC), 1.0 * NSEC_PER_SEC, 0);
//要执行的时间
dispatch_source_set_event_handler(self.timer, ^{
    NSLog(@"多久打印一次");
});
//运行GSD
dispatch_resume(self.timer);
//取消定时器
//dispatch_cancel(self.timer); self.timer = nil;复制代码

总结

本节我们主要简单的梳理了GCD的一些实用API,可以发现这些API是纯c语言的,并且相关API繁多,在实际编码过程中即使有代码提示,往往编码效率还是比较慢的,造成一定的使用门槛。当然,你也通过自定义代码块来提升效率。

原创声明,本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

相关文章

  • GCD梳理与总结——封装

    通过梳理,我们可以发现,其实GCD的概念并不是很复杂,只是初学者往往会被它C语言的大串API以及网上各种很绕的概念给唬住了。剖开表象,看本质。GCD(Grand...

    ios-lan
  • 2022年iOS程序员最新面试指南

    大家好,最近我刚换了一份工作,过完年回来就是金三银四了,相信有很多小伙伴都蠢蠢欲动,想要换一份高薪厚禄的工作,不想再卷了~

    动动我试试
  • 定时器 你真的会使用吗?

    这两种方法都是创建一个定时器,区别是用timerWithTimeInterval:方法创建的定时器需要手动加入RunLoop中。

    零式的天空
  • 《精进》4 怎样的学习,才能够直面现实 如何成为一个高段位的学习者

    yeedomliu
  • iOS Dev Fundamentals

    iOS中常用的Networking技术主要包括HTTP(s)及TCP,前者主要的API封装在URL Loading System中,后者API主要封装在CFNe...

    conanma
  • iOS 从实际出发理解多线程

    前言 ----       多线程很多开发者多多少少相信也都有了解,以前有些东西理解的不是很透,慢慢的积累之后,这方面的东西也需要自己好好的总结一下。多线程从我...

    Mr.RisingSun
  • iOS定时器,你真的会使用吗?前言正文结语

    BY
  • RunLoop总结:RunLoop 与GCD 、Autorelease Pool之间的关系

    如果在面试中问到RunLoop相关的知识,很有可能也会问到RunLoop与GCD、Autorelease Pool有没有关系,哪些地方用到了GCD、Autore...

    Haley_Wong
  • iOS——GCD的死锁案例

    在项目中,用GCD的时候非常多,但是我最近脑子里一直在问自己一个问题,死锁是什么。惭愧的是这个当初清晰的概念现在愈加模糊,考虑到自己并没有专门整理过死锁的文章,...

    Originalee
  • 我的2020 九月iOS面试秘籍,为你的跳槽保驾护航

    开门见山,这篇文章,适合「中高级iOS开发」,如果你现在待业,或者想跳槽并且还在求职的话,可以看看本文,找一找灵感,希望对你们有帮助。

    编程怪才-凌雨画
  • GCD API 理解 (一)资料先行

    GCD 深入理解:第一部分 GCD 深入理解:第二部分 以上两篇文章是关于GCD讲的比较好的文章,翻译自raywenderlich,该网站有很多关于iOS ...

    Haley_Wong
  • 自学iOS开发,从新手小白到高级工程师正确的打开方式

    自己目前大四汪一枚,自学iOS开发一年左右,先后学习了swift和Objective-C。由于是自学(而且全院貌似就我一个人在学),深知自学之痛。所以在此分享一...

    企鹅号小编
  • 掌握SpringBoot-2.3的容器探针:基础篇

    为了让应用更适应容器化环境,SpringBoot2.3版本推出了新的探针技术,《掌握SpringBoot-2.3的容器探针》系列旨在与您一起学习和实践这些新技术...

    程序员欣宸
  • iOS多线程NSThread,NSOperation和GCD详解

    http://blog.csdn.net/shenjie12345678/article/details/51819493

    HelloWorld杰少
  • 深入学习iOS定时器

    定时器,用来延迟或重复执行某些方法,例如:网络定时刷新,UI间隔刷新,动画效果......iOS中的定时器大致分为这几类: <pre> NSObject ...

    sweet说好的幸福
  • ToB规模化销售是如何炼成的?

    来源:硅谷销售研究院 |作者:Patrick ---- 规模化销售不是一天炼成的,但是有科学的方法和路径可以做到。 先说几个最近当面和微信聊天里的咨询客户...

    腾讯SaaS加速器

扫码关注腾讯云开发者

领取腾讯云代金券