GCD

GCD —— Grand Central Dispatch

  • 是基于C语言的底层API
  • 用Block定义任务,将任务添加到线程中使用。集中管理

1、GCD的执行函数

//同步
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
  • [x]queue:队列:用来存放任务
  • [x]block:任务:要执行的操作
//异步
dispatch_async(dispatch_deququ_t queue, dispatch_block_t block);
  • [x]同步:在当前线程中执行,不具备创建线程的功能
  • [x]异步:在新的线程中执行,具备开启新线程的功能
全局并发队列 手动创建串行队列 主队列
同步(sync) 不开线程串行 不开线程串行 不开线程串行
异步(async) 可能开线程并行 开线程串行 不开线程串行
/*
同步 + 主队列 = 需要记住的就一点: 同步函数不能搭配主队列使用
注意: 如果是在子线程中调用同步函数 + 主对列 是可以执行的
*/

2、GCD队列

并发队列

不用手动创建,直接获取全局的并发队列就可以

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORUTY_DEFAULT,0);

其中,参数0是预留参数,现在没用。

串行队列

获取串行队列

  • 方式一:手动创建
/**
* 创建一个串行队列
*
* @param label#> 队列的标示字符串 description#>
* @param attr#> 初始化队列的属性 description#>
*
* @return 创建好得串行队列
*/
dispatch_queue_t queue = dispatch_queue_create("xyl.queue", NULL); //非ARC下需要手动释放创建的队列
dispatch_release(queue);
  • 方式二:获得主队列

获取GCD主队列,主队列是和串行的和主线程相关的队列。

主队列都是串行

// 如果任务放在主队列中, 哪怕是异步方法也不会创建新的线程
dispatch_get_main_queue();

3、前面1和2结合起来的例子:

/*
异步 + 并行 = 会开启新的线程
*/ //获取全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//将任务添加到全局的异步队列中执行
dispatch_async(queue, ^{
NSLog(@"任务%@", [NSThread mainThread]);
});
/*
异步 + 串行 = 会创建新的线程, 但是只会创建一个新的线程, 所有的任务都在这一个新的线程中执行
异步任务, 会先执行完所有的代码, 再在子线程中执行任务
*/ dispatch_queue_t queue = dispatch_queue_create("xyl.queue", NULL);
dispatch_async(queue, ^{
NSLog(@"-----download-----%@",[NSThread mainThread]);
});
参数:
  • DISPATCH_QUEUE_SERIAL (or NULL) 串行队列

  • DISPATCH_QUEUE_CONCURRENT 并行

4、GCD的线程之间通讯

如果是通过异步函数调用, 那么会先执行完所有的代码, 再更新UI

如果是同步函数调用, 那么会先更新UI, 再执行其它代码

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//子线程中下载图片
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data]; dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 如果是通过异步函数调用, 那么会先执行完所有的代码, 再更新UI
// 如果是同步函数调用, 那么会先更新UI, 再执行其它代码
dispatch_async(mainQueue, ^{
//主线程拿到图片进行设置
[self.button setImage:image forStatus:UIControlStateNormal];
});
});

5、延迟执行

在程序中,我们经常会遇到希望间隔一段时间再做某件事,下面我们来看看几种方法的实现:

  • 睡眠方式(缺点明显:阻塞当前线程)
// 延迟执行不要用sleep,坏处:卡住当前线程
[NSThread sleepForTimeInterval:3];
  • 定制延迟任务
// 一旦定制好延迟任务后,不会卡主当前线程
[self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];

这种方法可以很好的实现需要的延迟功能,但是只能在当前线程中执行,不能灵活的控制执行的线程

  • GCD方式
// 3秒后回到主线程执行block中的代码
dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), mainQueue, ^{ NSLog(@"------task------%@", [NSThread currentThread]); }); // 3秒后自动开启新线程 执行block中的代码
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{ NSLog(@"------task------%@", [NSThread currentThread]); });

GCD方式,既可以实现延迟执行,也可以实现控制任务在不同的线程中执行,方便好用。

6、GCD代码运行时只执行一次

在程序运行的过程中,经常会遇到希望某段代码只执行一次。我们除了可以使用设置一个BOOL变量控制以外,还能使用GCD方式,简单方便

static dispatch_once_t onoceToken;
dispatch_once(&onceToken, ^{
//执行一次的代码
});

快捷方式:上面的代码块只写dispatch_once就会全部出现。

7、队列组

如果想要多个并发的线程事件完成之后,再执行某一个事件,就可以使用队列组,将先执行的多个事件线程放在队列组里面先执行。例如:将多个图片下载完成后,再使用图片的时候,如果不用队列组,会很麻烦。

举例:


// 1.队列组
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 2.下载图片1
__block UIImage *image1 = nil;
dispatch_group_async(group, queue, ^{
NSURL *url1 = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee460de6182ff5e0fe99257e80.jpg"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
image1 = [UIImage imageWithData:data1];
}); // 3.下载图片2
__block UIImage *image2 = nil;
dispatch_group_async(group, queue, ^{
NSURL *url2 = [NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
image2 = [UIImage imageWithData:data2];
}); // 4.合并图片 (保证执行完组里面的所有任务之后,再执行notify函数里面的block)
dispatch_group_notify(group, queue, ^{
// 开启一个位图上下文
UIGraphicsBeginImageContextWithOptions(image1.size, NO, 0.0); // 绘制第1张图片
CGFloat image1W = image1.size.width;
CGFloat image1H = image1.size.height;
[image1 drawInRect:CGRectMake(0, 0, image1W, image1H)]; // 绘制第2张图片
CGFloat image2W = image2.size.width * 0.5;
CGFloat image2H = image2.size.height * 0.5;
CGFloat image2Y = image1H - image2H;
[image2 drawInRect:CGRectMake(0, image2Y, image2W, image2H)]; // 得到上下文中的图片
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文
UIGraphicsEndImageContext(); // 5.回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = fullImage;
});
});

8、栅栏

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

这个queue不能是全局的并发队列

  • 如果所有的任务都在"同一个"队列中,f 那么在barrier方法之前添加的任务会先被执行, 只有等barrier方法之前添加的任务执行完毕, 才会执行barrier

  • 而且如果是在barrier方法之后添加的任务, 必须等barrier方法执行完毕之后才会开始执行

  • 要想执行完前面所有的任务再执行barrier必须满足两个条件

    • 1、 所有任务都是在同一个队列中
    • 2、 队列不能是全局并行队列, 必须是自己创建的队列
dispatch_barrier_async(queue, ^{
}

9、GCD快速迭代

/*
第一个参数: 需要执行几次任务
第二个参数: 队列
第三个参数: 当前被执行到得任务的索引
*/ dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%@, %zd",[NSThread currentThread] , index);
});

例子:将一个文件夹中的文件,拷贝到另一个文件夹

    // 1.获取images文件夹中所有的文件
NSString *sourcePath = @"/Users/apple/Desktop/abc";
NSString *dest = @"/Users/apple/Desktop/lnj"; // 2.获取images文件夹中所有的文件
NSFileManager *mgr = [NSFileManager defaultManager];
NSArray *subPaths = [mgr subpathsAtPath:sourcePath]; // 3.剪切文件到lnj文件夹中 CFAbsoluteTime begin = CFAbsoluteTimeGetCurrent();
dispatch_apply(4, dispatch_get_global_queue(0, 0), ^(size_t index) { // 3.1获取当前遍历到得文件的名称
NSString *fileNmae = subPaths[index];
// 3.2根据当前文件的名称, 拼接全路径
NSString *fromPath = [sourcePath stringByAppendingPathComponent:fileNmae];
NSString *toPath = [dest stringByAppendingPathComponent:fileNmae];
NSLog(@"fromPath = %@", fromPath);
NSLog(@"toPath = %@", toPath);
NSLog(@"ddd");
[mgr moveItemAtPath:fromPath toPath:toPath error:nil]; });
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();

iOS-GCD多线程的更多相关文章

  1. iOS——GCD多线程

    1> 概述 Grand Central Dispatch (GCD)是Apple开发的一种多核编程技术.主要用于优化应用程序以支持多核处理器以及其他对称多处理系统. GCD提供函数实现多线程开发 ...

  2. iOS GCD多线程介绍

    GCD:是纯C语言写的,是苹果公司为多核的并行运算提出的解决方案. GCD的两个核心概念: - 任务 - 队列 将任务添加到队列中 GCD会自动将队列中的任务取出,放到对应的线程中执行 任务的取出遵循 ...

  3. iOS 开发多线程篇—GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  4. iOS开发多线程篇—GCD介绍

    iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...

  5. iOS开发多线程篇—GCD的基本使用

    iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进 ...

  6. iOS开发多线程篇—GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  7. ios开发:GCD多线程

    ios有三种多线程编程技术,分别是NSThread,Cocoa NSOperation和GCD,GCD全称Grand Central Dispatch 是Apple开发的一个多核编程的解决方法,在iO ...

  8. iOS开发——GCD多线程详解

    GCD多线程详解 1. 什么是GCD Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,简单来说,GCD就是iOS一套解决多线程的机制,使用GCD能够最大限度简化多线程 ...

  9. iOS之多线程开发NSThread、NSOperation、GCD

    原文出处: 容芳志的博客   欢迎分享原创到伯乐头条 简介iOS有三种多线程编程的技术,分别是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全称:Grand Centr ...

  10. iOS开发多线程篇—GCD简介

    iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...

随机推荐

  1. Eclipse使用jre的原理与配置

    近期要配置Eclipse环境,Mark当中的一些方法. 下载Eclipse SDK之后我们就要关联JRE,由于Eclipse启动须要JRE. Eclipse启动时寻找JRE的顺序: 1.假设eclip ...

  2. Citrix 服务器虚拟化之二十八 XenApp6.5发布文档内容

    Citrix 服务器虚拟化之二十八  XenApp 6.5发布文档内容 XenApp可发布以下类型的资源向用户提供信息访问,这些资源可在服务器或桌面上虚拟化: 1)  服务器桌面:发布场中服务器的整个 ...

  3. [Angular 2] Select From Multiple Nested Angular 2 Elements

    You have complete control over the elements you nest inside of your component instance by using sele ...

  4. Swift 编程风格指南(raywenderlich.com 版本号)

    官方 raywenderlich.com Swift 编程风格指南 本文版权归 raywenderlich.com .The Official raywenderlich.com Swift Styl ...

  5. 如何恢复 Linux 上删除的文件,第 1 部分

    来源:http://www.ibm.com/developerworks/cn/linux/l-cn-filesrc/ 原理及普通文件的恢复 要想恢复误删除的文件,必须清楚数据在磁盘上究竟是如何存储的 ...

  6. NopCmmerce Area前后台分离

    Nop 前后台是独立的应用程序:使用用Area技术分离:Nop.Admin项目放在Nop.Web项目的administration文件夹下面,通过编辑类库输入路径到Nop.Web的Bin目录下面: 分 ...

  7. 全栈一路坑之使用django创建博客

    最近在看一篇全栈增长工程师实战,然后学习里面的项目,结果发现作者用的技术太过老旧,好多东西都已经被抛弃了,所以结合着官方文档和自己的一些理解将错误的信息替换一下,边写边学习 准备工作和工具 作者说需要 ...

  8. linux用户权限

    Linux下passwd和shadow文件内容详解 一./etc/passwd/etc/passwd 文件是一个纯文本文件,每行采用了相同的格式: name:password:uid:gid:comm ...

  9. spring mvc使用的一些注意事项

    一天不进步,就是退步! 1.静态文件的处理 可以使用<mvc:resources mapping="/static/**" location="/WEB-INF/s ...

  10. ios uitableviewcell动态计算高度

    #import <UIKit/UIKit.h> @interface TestCell : UITableViewCell @property (weak, nonatomic) IBOu ...