iOS-GCD多线程
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多线程的更多相关文章
- iOS——GCD多线程
1> 概述 Grand Central Dispatch (GCD)是Apple开发的一种多核编程技术.主要用于优化应用程序以支持多核处理器以及其他对称多处理系统. GCD提供函数实现多线程开发 ...
- iOS GCD多线程介绍
GCD:是纯C语言写的,是苹果公司为多核的并行运算提出的解决方案. GCD的两个核心概念: - 任务 - 队列 将任务添加到队列中 GCD会自动将队列中的任务取出,放到对应的线程中执行 任务的取出遵循 ...
- iOS 开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- iOS开发多线程篇—GCD介绍
iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...
- iOS开发多线程篇—GCD的基本使用
iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进 ...
- iOS开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- ios开发:GCD多线程
ios有三种多线程编程技术,分别是NSThread,Cocoa NSOperation和GCD,GCD全称Grand Central Dispatch 是Apple开发的一个多核编程的解决方法,在iO ...
- iOS开发——GCD多线程详解
GCD多线程详解 1. 什么是GCD Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,简单来说,GCD就是iOS一套解决多线程的机制,使用GCD能够最大限度简化多线程 ...
- iOS之多线程开发NSThread、NSOperation、GCD
原文出处: 容芳志的博客 欢迎分享原创到伯乐头条 简介iOS有三种多线程编程的技术,分别是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全称:Grand Centr ...
- iOS开发多线程篇—GCD简介
iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...
随机推荐
- CSS Sprites图片处理
简介: CSS Sprites是一个网页图片处理方式,在国内都叫CSS精灵,css Sprites允许你将一个页面涉及到的所有零星图片都包含到一张大图中去,这样一来,当访问该页面时,载入的图片就不会像 ...
- js验证身份证id
function isCardNo(card) { // 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X var reg = /(^\d{1 ...
- iOS开发——实用技术OC篇&8行代码教你搞定导航控制器全屏滑动返回效果
8行代码教你搞定导航控制器全屏滑动返回效果 前言 如果自定了导航控制器的自控制器的leftBarButtonItem,可能会引发边缘滑动pop效果的失灵,是由于 self.interactivePop ...
- ORACLE AUTOMATIC STORAGE MANAGEMENT翻译-第二章ASM Instance(4)完
ASM安全 这个小节主要描写叙述与ASM相关的各种安全配置话题,像 配置ASM须要的userids.groupids:ASM权限如 SYSOPER,SYSDBA和新的SYSASM权限,最后还有ASM ...
- 想了解JAVA的,看看(转载)
较新一篇 / 较旧一篇 编辑 |删除 | 复制链接 公开 想了解JAVA的,看看(转载)2009-03-01 15:41 (分类:默认分类) 先总结一下: J2SE (Core/Desktop) ...
- java 删除字符串中的反斜杠\
Java中有时候会打印出来会含有反斜杠(\)的字符串,我们需要删除时,可以使用 replace() 或 replaceAll() 但是要注意的是replaceAll()里面用的是正则表达式,所以一个斜 ...
- 2.1.4 扫描器X-Scan查本机隐患
X-Scan是由安全焦点开发的一个功能强大的扫描工具.它采用多线程方式对指定IP地址段(或单机)进行安全漏洞检测,支持插件功能. 1.用X-Scan查看本机IP地址 利用X-Scan扫描器来查看本机的 ...
- 【HTML5 2】《html5 开发精要与实例讲解》 step1 -- 导读
一.教程重点:以 综合性案例 为导向,辅之以 精要知识点 二.内容概况: 第1部分:通过 大小型案例 对 各重要知识点 进行详细讲解 第2部分:jWebSocket.RGraph.WebGL 三个重要 ...
- centos下cp -r 命令可拷贝文件夹
LINUX命令的cp -r 和-R的区别 功能上是等价的.不加-r或者-R的时候,只拷贝文件,不拷贝文件夹:加上后则会拷贝文件夹——包括下一级的子文件夹,以及子文件夹中的子文件夹,余此类推.rm的-R ...
- Hive编程(影印版)
<Hive编程(影印版)> 基本信息 原书名:Programming Hive 作者: Edward Capriolo Dean Wampler Jason Rutherglen 出版社: ...