iOS多线程编程(四)------ GCD(Grand Central Dispatch)
一、简单介绍
是基于C语言开发的一套多线程开发机制。也是眼下苹果官方推荐的多线程开发方法。用起来也最简单。仅仅是它基于C语言开发,并不像NSOperation是面向对象的开发。而是全然面向过程的。假设使用GCD,全然由系统管理线程,我们不须要编写线程代码。仅仅需定义想要运行的任务,然后加入到适当的调度队列(dispatch_queue).GCD会负责创建线程和调度你的任务。系统会直接提供线程管理。
二、任务和队列
GCD中有两个核心概念
(1)任务:运行什么操作
(2)队列:用来存放任务
GCD的使用就两个步骤
(1)定制任务
(2)确定想做的事情
将任务加入到队列中,GCD会自己主动将队列中的任务取出,放到相应的线程中运行
提示:任务的取出遵循队列的FIFO原则:先进先出。后进后出
三、运行任务
1、GCD中有2个用来运行任务的函数
说明:把右边的參数(任务)提交给左边的參数(队列)进行运行
(1)用同步的方式运行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
參数说明:queue:队列; block:任务
(2)用异步的方式运行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
2、同步和异步的差别
同步:在当前线程中运行
异步:在还有一条线程中运行
四、队列
1、GCD的队列能够分为2大类型
(1)并发队列(Concurrent Dispatch Queue):能够让多个任务并发(同一时候)运行(自己主动开启多个线程同一时候运行任务)并发功能仅仅有在异步(dispatch_async)函数才有效
(2)串行队列(Serial Dispatch Queue):让任务一个接着一个地运行(一个任务运行完毕后,再运行下一个任务)
2、补充说明
有4个术语比較easy混淆:同步、异步、并发、串行(在博客 多线程编程(-)—-概念 也提到了)
同步和异步决定了要不要开启新的线程
同步:在当前线程中运行任务,不具备开启新线程的能力
异步:在新的线程中运行任务。具备开启新线程的能力
并发和串行决定了任务的运行方式
并发:多个任务并发运行
串行:一个任务运行完毕后,再运行下一个任务
五、(同步/异步)串行队列和(同步/异步)并发队列开启线程的总结 (代码演示样例)
说明:
(1)同步函数不具备开启线程的能力,不管是什么队列都不会开启线程;异步函数具备开启线程的能力,开启几条线程有队列决定(串行队列仅仅会开启一条新的线程,并发队列会开启多条线程)
(2) MRC下凡是函数中。各种函数名中带有create\copy\new\retain等字眼。都须要在不须要使用这个数据的时候进行release
ARC下GCD的数据类型不须要再作release
CF(core Foundation)的数据在ARC环境下还是须要release
(3) 异步函数具备开线程的能力,但不一定会开线程
1、异步并发队列(同一时候开启N个线程)
/**
* 异步并发队列
*/
- (void)asynchronousConcurrent{
NSLog(@"异步函数往并发队列中加入任务");
NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);
// 1、创建并发队列
// 方法一 和创建串行队列一样
// dispatch_queue_t queue = dispatch_queue_create("asynConcurrent", DISPATCH_QUEUE_CONCURRENT);
// 方法二 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2、加入任务到队列
dispatch_async(queue, ^{
NSLog(@"下载图片1 ------ %@", [NSThread currentThread]);
[self loadImage:1];
});
dispatch_async(queue, ^{
NSLog(@"下载图片2------ %@", [NSThread currentThread]);
[self loadImage:2];
});
dispatch_async(queue, ^{
NSLog(@"下载图片3 ------ %@", [NSThread currentThread]);
[self loadImage:3];
});
NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);
// 打印结果 开启多个线程,并发运行。
没有先后顺序(有的话也是刚好巧合而已) 能够看number 能够看做线程值
/**
第一次运行
2016-08-24 12:53:24.026 YJGCDDemo[1220:24092] 异步函数往并发队列中加入任务
2016-08-24 12:53:24.027 YJGCDDemo[1220:24092] 主线程1111 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main}
2016-08-24 12:53:24.027 YJGCDDemo[1220:24092] 主线程2222 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main}
2016-08-24 12:53:24.027 YJGCDDemo[1220:24126] 下载图片1 ------ <NSThread: 0x7f81baf25e90>{number = 2, name = (null)}
2016-08-24 12:53:24.027 YJGCDDemo[1220:24128] 下载图片2------ <NSThread: 0x7f81bacc5fe0>{number = 3, name = (null)}
2016-08-24 12:53:24.027 YJGCDDemo[1220:24127] 下载图片3 ------ <NSThread: 0x7f81baf81ac0>{number = 4, name = (null)}
第二次运行
2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 异步函数往并发队列中加入任务
2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 主线程1111 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main}
2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 主线程2222 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main}
2016-08-24 12:53:32.427 YJGCDDemo[1220:24126] 下载图片2------ <NSThread: 0x7f81baf25e90>{number = 2, name = (null)}
2016-08-24 12:53:32.427 YJGCDDemo[1220:24260] 下载图片3 ------ <NSThread: 0x7f81baf7f660>{number = 7, name = (null)}
2016-08-24 12:53:32.427 YJGCDDemo[1220:24153] 下载图片1 ------ <NSThread: 0x7f81baf81ac0>{number = 6, name = (null)}
*/
}
2、异步串行队列(会开启线程,可是仅仅开启一个线程)
/**
* 异步串行队列
*/
- (void)asynchronousSerial{
NSLog(@"用异步函数往串行队列中加入任务");
NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);
//1. 创建串行队列
dispatch_queue_t queue = dispatch_queue_create("asynSerial", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"下载图片1 --- %@", [NSThread currentThread]);
[self loadImage:1];
});
dispatch_async(queue, ^{
NSLog(@"下载图片2 --- %@", [NSThread currentThread]);
[self loadImage:2];
});
dispatch_async(queue, ^{
NSLog(@"下载图片3 --- %@", [NSThread currentThread]);
[self loadImage:3];
});
NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);
// 打印结果:异步串行队列,会开启一个线程,顺序运行。 看运行结果也能够看出,图片是一张下载完在下载下一张的。
/**
2016-08-24 12:39:14.195 YJGCDDemo[942:16507] 用异步函数往串行队列中加入任务
2016-08-24 12:39:14.196 YJGCDDemo[942:16507] 主线程1111 ---- <NSThread: 0x7f8ed1f05f90>{number = 1, name = main}
2016-08-24 12:39:14.196 YJGCDDemo[942:16507] 主线程2222 ---- <NSThread: 0x7f8ed1f05f90>{number = 1, name = main}
2016-08-24 12:39:14.196 YJGCDDemo[942:16622] 下载图片1 --- <NSThread: 0x7f8ed1c43c00>{number = 2, name = (null)}
2016-08-24 12:39:14.261 YJGCDDemo[942:16622] 下载图片2 --- <NSThread: 0x7f8ed1c43c00>{number = 2, name = (null)}
2016-08-24 12:39:14.303 YJGCDDemo[942:16622] 下载图片3 --- <NSThread: 0x7f8ed1c43c00>{number = 2, name = (null)}
*/
}
3、同步并发队列(不会开启新的线程,并发队列失去并发的功能)
/**
* 同步并发队列
*/
- (void)synchronousConcurrent{
NSLog(@"用同步函数往并发队列中加入任务");
NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);
// 1.创建并发队列
// 方式一 一般都使用这样的方式获取
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 方式二 和创建串行队列一样
dispatch_queue_t queue = dispatch_queue_create("syncConcurrentncy", DISPATCH_QUEUE_CONCURRENT);
// 2.加添任务到队列
dispatch_sync(queue, ^{
NSLog(@"下载图片1 ---- %@", [NSThread currentThread]);
[self loadImage:1];
});
dispatch_sync(queue, ^{
NSLog(@"下载图片2 ---- %@", [NSThread currentThread]);
[self loadImage:2];
});
dispatch_sync(queue, ^{
NSLog(@"下载图片3 ---- %@", [NSThread currentThread]);
[self loadImage:3];
});
NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);
// 打印结果 和同步串行队列一样 这边并发队列效果失效,不会开启线程。
/**
2016-08-24 11:20:44.153 YJGCDDemo[43913:3002870] 用同步函数往并发队列中加入任务
2016-08-24 11:20:44.154 YJGCDDemo[43913:3002870] 主线程1111 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
2016-08-24 11:20:44.154 YJGCDDemo[43913:3002870] 下载图片1 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
2016-08-24 11:20:44.433 YJGCDDemo[43913:3002870] 下载图片2 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
2016-08-24 11:20:44.475 YJGCDDemo[43913:3002870] 下载图片3 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
2016-08-24 11:20:44.508 YJGCDDemo[43913:3002870] 主线程2222 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
*/
}
4、同步串行队列(不会开启新的线程)
/**
* 同步串行队列
*/
- (void)synchronousSerial{
NSLog(@"用同步函数往串行队列中加入任务");
NSLog(@"主线程111----- %@", [NSThread currentThread]);
// 1、创建串行队列 // DISPATCH_QUEUE_SERIAL 串行队列 也能够为NULL NULL时 默认是 串行队列; DISPATCH_QUEUE_CONCURRENT 并发队列
dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL);
// 2、加入任务到队列中运行
dispatch_sync(queue, ^{
// 此块代码没有不论什么意义,仅仅是为了体现同步串行队列的效果, 仅仅能运行完了 才干运行面下的。
for (int i = 0; i < 30000; i++) {
//
NSLog(@"%i", i);
}
NSLog(@"下载图片1 ---- %@", [NSThread currentThread]);
[self loadImage:1];
});
dispatch_sync(queue, ^{
for (int i = 0; i < 30000; i++) {
//
NSLog(@"%i", i);
}
NSLog(@"下载图片2 -- %@", [NSThread currentThread]);
[self loadImage:2];
});
dispatch_sync(queue, ^{
for (int i = 0; i < 30000; i++) {
//
NSLog(@"%i", i);
}
NSLog(@"下载图片3 -- %@", [NSThread currentThread]);
[self loadImage:3];
});
NSLog(@"主线程222----- %@", [NSThread currentThread]);
// 打印结果就是同步按顺序运行。
每一个任务按顺序运行,不开启线程
/**
2016-08-24 10:52:55.049 YJGCDDemo[43413:2986818] 用同步函数往串行队列中加入任务
2016-08-24 10:52:55.049 YJGCDDemo[43413:2986818] 主线程111----- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main}
2016-08-24 10:52:55.050 YJGCDDemo[43413:2986818] 下载图片1 ---- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main}
2016-08-24 10:52:55.580 YJGCDDemo[43413:2986818] 下载图片2 -- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main}
2016-08-24 10:52:55.616 YJGCDDemo[43413:2986818] 下载图片3 -- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main}
2016-08-24 10:52:55.644 YJGCDDemo[43413:2986818] 主线程222----- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main}
*/
}
六、经常用法 在Demo中的CommonMethodsViewCotroller类
1、后台运行
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// something
});
2、主线程运行
dispatch_async(dispatch_get_main_queue(), ^{
// something
});
3、一次性运行 dispatch_once()
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be execution once
NSLog(@"改行代码仅仅运行一次");
});
4、延迟N秒运行 (这边列举了四种方式) dispatch_time()
NSLog(@"打印线程----- %@", [NSThread currentThread]);
// 延时运行方式一 使用NSObject的方法
// 2秒后再调用self的run方法
// [self performSelector:@selector(loadImage) withObject:nil afterDelay:2.0];
// 延迟运行方式二 使用GCD函数
// 在同步函数中运行
// 注意 假设使用异步函数 dispatch_async 那么[self performSelector:@selector(loadImage) withObject:nil afterDelay:5.0]; 不会被运行
// dispatch_queue_t queue = dispatch_queue_create("yangjian.net.cn", 0);
// dispatch_sync(queue, ^{
// [self performSelector:@selector(loadImage) withObject:nil afterDelay:2.0];
// });
// 延迟运行方式三 能够安排其线程---> 主队列
// dispatch_queue_t queue = dispatch_get_main_queue();
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{
// NSLog(@"主队列--延迟运行------%@",[NSThread currentThread]);
// [self gcdLoadImage];
// });
// 延迟运行方式四 能够安排其线程---> 并发队列
//1、获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//2、计算任务运行的时间
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
//3、会在when这个时间点。运行queue中的这个任务
dispatch_after(when, queue, ^{
NSLog(@"并发队列--延迟运行 ---- %@", [NSThread currentThread]);
[self gcdLoadImage];
});
5、运行某个代码片段N次 dispatch_apply()
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(4, globalQueue, ^(size_t index) {
// 运行4次
});
6、队列组的使用 dispatch_group_async()
// 需求
//1 分别异步运行2个耗时的操作
//2 等两个异步操作都运行完毕后,再回到主线程运行操作
// 假设想要高速高效地实现上述需求,能够考虑用队列组
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
// 并发运行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
// 并发运行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
// 等前面的异步操作都运行完毕后,回到主线程
});
6、dispatch_barrier_async()
/**
* 使用此方法创建的任务首先会查看队列中有没有别的任务要运行。假设有。则会等待已有任务运行完毕再运行;同一时候在此方法后加入的任务必须等待此方法中任务运行后才干运行。(利用这种方法能够控制运行顺序,比如前面先载入最后一张图片的需求就能够先使用这种方法将最后一张图片载入的操作加入到队列,然后调用dispatch_async()加入其它图片载入任务)
*/
- (void)barrier{
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue = dispatch_queue_create("RICHARD", DISPATCH_QUEUE_CONCURRENT); // 创建并发队列
dispatch_async(queue, ^{
NSLog(@"下载图片1 --- %@", [NSThread currentThread]);
UIImage *image = [self requestImageData:@"http://atth.eduu.com/album/201203/12/1475134_1331559643qMzc.jpg"];
// 回到主线程
dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
dispatch_async(mainQueue1, ^{
self.imageViewOne.image = image;
});
});
dispatch_async(queue, ^{
NSLog(@"下载图片2 --- %@", [NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async 下载图片3 --- %@", [NSThread currentThread]);
UIImage *image = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
dispatch_async(main_queue, ^{
self.imageViewThree.image = image;
});
});
dispatch_async(queue, ^{
NSLog(@"下载图片4 --- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载图片5 --- %@", [NSThread currentThread]);
UIImage *image = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
dispatch_async(main_queue, ^{
self.imageViewTwo.image = image;
});
});
// 打印结果分析:1、 12 运行玩完 运行3 再运行45 2、 12顺序不定 45顺序不定
/**
2016-08-25 10:47:00.560 YJGCDDemo[4436:367515] 下载图片2 --- <NSThread: 0x7ff720f13ac0>{number = 47, name = (null)}
2016-08-25 10:47:00.560 YJGCDDemo[4436:367518] 下载图片1 --- <NSThread: 0x7ff720e1c5d0>{number = 48, name = (null)}
2016-08-25 10:47:00.560 YJGCDDemo[4436:367102] dispatch_barrier_async 下载图片3 --- <NSThread: 0x7ff720d9b7d0>{number = 43, name = (null)}
2016-08-25 10:47:00.560 YJGCDDemo[4436:367293] 下载图片4 --- <NSThread: 0x7ff720c9e250>{number = 45, name = (null)}
2016-08-25 10:47:00.560 YJGCDDemo[4436:367516] 下载图片5 --- <NSThread: 0x7ff720dba290>{number = 46, name = (null)}
*/
}
七、代码演示样例 在Demo中的CommonMethodsViewCotroller类
下载两张照片完后,合并照片。
(两种方式)
/**
* 合并图片(方式一)
*/
- (void)mergeImage{
// // 获取全局并发队列
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//
// // 获取主队列
// dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(global_queue, ^{
// 下载图片1
UIImage *image1 = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
NSLog(@"图片1下载完毕----%@", [NSThread currentThread]);
UIImage *image2 = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
NSLog(@"图片2下载完毕----%@", [NSThread currentThread]);
// 回到主线程显示图片
dispatch_async(main_queue, ^{
NSLog(@"显示图片---%@", [NSThread currentThread]);
self.imageViewOne.image = image1;
self.imageViewTwo.image = image2;
// 合并两张图片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
[image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];
[image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];
self.imageViewThree.image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
NSLog(@"图片合并完毕----%@", [NSThread currentThread]);
});
});
// 打印结果 须要等图片1下载完 在下载图片2 再回到主线程
/**
2016-08-24 16:58:40.123 YJGCDDemo[3480:125975] 图片1下载完毕----<NSThread: 0x7ff65acd85f0>{number = 3, name = (null)}
2016-08-24 16:58:40.319 YJGCDDemo[3480:125975] 图片2下载完毕----<NSThread: 0x7ff65acd85f0>{number = 3, name = (null)}
2016-08-24 16:58:40.319 YJGCDDemo[3480:125910] 显示图片---<NSThread: 0x7ff65ad00dd0>{number = 1, name = main}
2016-08-24 16:58:40.335 YJGCDDemo[3480:125910] 图片合并完毕----<NSThread: 0x7ff65ad00dd0>{number = 1, name = main}
*/
// 效率不高 须要等图片1,图片2都下载完了后才合并
// 优化 使用队列组能够让图片1 图片2的下载任务同事进行,且当两个下载任务都完毕的时候回到主线程进行显示。
}
/**
* 使用队列组解决(方式二)
*/
- (void)groupMergeImage{
//步骤
// 1、创建一个队列组
// 2、开启一个任务下载图片1
// 3、开启一个任务下载图片2
// 同一时候运行下载图片1 和 下载图片2操作
// 4、等group中的全部任务都运行完毕,再回到主线程运行其它操作
// 1、创建一个队列租
dispatch_group_t group = dispatch_group_create();
// 2、开启一个任务下载图片1
__block UIImage *image1 = nil;
dispatch_group_async(group, global_queue, ^{
image1 = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
NSLog(@"图片1下载完毕--- %@", [NSThread currentThread]);
});
// 3、开启一个任务下载图片2
__block UIImage *image2 = nil;
dispatch_group_async(group, global_queue, ^{
image2 = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
NSLog(@"图片2下载完毕--- %@", [NSThread currentThread]);
});
// 同一时候运行下载图片1\下载图片2操作
// 4、等group重的全部任务都运行完毕,再回到主线程运行其它操作
dispatch_group_notify(group, main_queue, ^{
NSLog(@"显示图 --- %@", [NSThread currentThread]);
self.imageViewOne.image = image1;
self.imageViewTwo.image = image2;
// 合并两张图片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
[image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];
[image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];
self.imageViewThree.image = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
NSLog(@"图片合并完毕 --- %@", [NSThread currentThread]);
});
// 同一时候开启两个线程 分别下载图片 会比上面的效率高一点
/**
2016-08-24 16:58:03.785 YJGCDDemo[3467:125346] 图片1下载完毕--- <NSThread: 0x7f8d13cc61c0>{number = 3, name = (null)}
2016-08-24 16:58:03.978 YJGCDDemo[3467:125349] 图片2下载完毕--- <NSThread: 0x7f8d13ece620>{number = 4, name = (null)}
2016-08-24 16:58:03.978 YJGCDDemo[3467:125303] 显示图 --- <NSThread: 0x7f8d13e052b0>{number = 1, name = main}
2016-08-24 16:58:03.995 YJGCDDemo[3467:125303] 图片合并完毕 --- <NSThread: 0x7f8d13e052b0>{number = 1, name = main}
*/
}
八、线程间通信
// 从子线程回到主线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 运行耗时的异步操作
dispatch_async(dispatch_get_main_queue(), ^{
//回到主线程,运行UI刷新操作
});
});
九、Operation和GCD的对照
长处: 不须要关心线程管理。数据同步的问题;
差别:
1、性能:GCD更接近底层。而NSOperation则更高级抽象,所以GCD在追求性能的底层操作来说。是速度最快的。
2、从异步操作之间的事务性,顺序行,依赖关系。GCD须要自己写很多其它的代码来实现,而NSOperationQueue已经内建了这些支持
3、假设异步操作的国学很多其它的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。
底层代码中。任务之间不太互相依赖。而须要更高的并发能力,GCD则更有优势
十、总结
学了两天,对gcd有一些的了解。能在项目中使用多线程。只是这边也要避免非常多死锁的问题,后期有时间再整理出来。四天左右把iOS多线程的几种方法都整理了下,写了demo。也算对自己的一个小小总结。
总结两点:
1、线程运行方式
dispatch_async 异步运行
dispatch_sync 同步运行
dispatch_delay 延迟运行
2、处理任务对象
dispatch_get_main_queue 主线程队列(UI线程队列)
dispatch_get_global_queue 并发线程队列
串行队列
demo地址: http://download.csdn.net/detail/yj229201093/9611939
參考链接:http://www.cnblogs.com/wendingding/p/3806821.html
感谢各路大神的博客,学无止境…
iOS多线程编程(四)------ GCD(Grand Central Dispatch)的更多相关文章
- IOS学习之十七:Grand Central Dispatch(GCD)编程基础
IOS学习之十七:Grand Central Dispatch(GCD)编程基础 有过编程经验的人,基本都会接触到多线程这块. 在java中以及Android开发中,大量的后台运行,异步消息队列, ...
- GCD (Grand Central Dispatch) 笔记
GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式. 在Mac OS X 10.6和IOS 4.0之后开 ...
- iOS开发-多线程之GCD(Grand Central Dispatch)
Grand Central Dispatch(GCD)是一个强有力的方式取执行多线程任务,不管你在回调的时候是异步或者同步的,可以优化应用程序支持多核心处理器和其他的对称多处理系统的系统.开发使用的过 ...
- iOS多线程编程Part 3/3 - GCD
前两部分介绍了NSThread.NSRunLoop和NSOperation,本文聊聊2011年WWDC时推出的神器GCD.GCD: Grand Central Dispatch,是一组用于实现并发编程 ...
- iOS多线程编程技术之NSThread、Cocoa NSOperation、GCD
原文出处: 容芳志的博客 简介iOS有三种多线程编程的技术,分别是:(一)NSThread(二)Cocoa NSOperation(三)GCD(全称:Grand Central Dispatch) 这 ...
- iOS多线程开发之GCD(基础篇)
总纲: GCD基本概念 GCD如何实现 GCD如何使用 队列和任务组合 一.GCD基本概念 GCD 全称Grand Central Dispatch(大中枢队列调度),是一套低层API,提供了⼀种新的 ...
- IOS高级编程之三:IOS 多线程编程
多线程的概念在各个操作系统上都会接触到,windows.Linux.mac os等等这些常用的操作系统,都支持多线程的概念. 当然ios中也不例外,但是线程的运行节点可能是我们平常不太注意的. 例如: ...
- iOS多线程知识总结--GCD
iOS多线程知识总结--GCD 1. iOS中苹果提供4钟方案来帮助我们实现多线程: (1) 纯C语言的pthread,偏底层,需要程序员手动管理线程的生命周期,基本不用. (2) OC语言的NSTr ...
- iOS多线程NSThread和GCD
在iOS中啊 其实有多种方法实现多线程 这里只记录两个比较常用的 或者说我比较常用的 一个就是BSThread 另一个就是一听名字就比较霸气的妇孺皆知的GCD 先说一下NSThread吧 这个方式 ...
- 转 Grand Central Dispatch 基础教程:Part 1/2 -swift
本文转载,原文地址:http://www.cocoachina.com/ios/20150609/12072.html 原文 Grand Central Dispatch Tutorail for S ...
随机推荐
- Knockout v3.4.0 中文版教程-12-控制文本内容和外观-html绑定
3. html绑定 目的 html绑定会使关联的DOM元素显示你参数指定的html内容. 当你的视图模型里面的值是HTML标记字符串,而你想要呈现它,这时候用html绑定特别合适. 例子 <di ...
- luogu3834 【模板】可持久化线段树 1(主席树)
关于空间,第零棵树是 \(4n\),其后每棵树都要多来 \(\log(n)\) 的空间,所以我是开 \(n(4+\log(n))\) 的空间. 关于借用节点: 图片来自这里 #include < ...
- GET 方法和 POST方法区别
两种 HTTP 请求方法:GET 和 POST 在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST. GET - 从指定的资源请求数据. POST - 向指定的资源提交 ...
- hdu2081
#include <stdio.h> #include <malloc.h> int main(){ ]; char *p; int t; p=(); scanf(" ...
- 九度oj 题目1102:最小面积子矩阵
题目描述: 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积) 输入: 每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K接下来 ...
- hihoCoder #1471 拥堵的城市
这道题目是hihoCoder Challenge 27的C题,我考虑了5天:(. 计数问题.由于树的结构的特殊性(树具有递归结构),不难想到思路是树形DP.由于这是[计数问题]而非[优化问题],我们思 ...
- SSD ECC中的LDPC编解码原理
转自:http://blog.csdn.net/zhuzongpeng/article/details/78899198 目前SSD中ECC纠错代码主要两种BCH和LDPC.不过,随着SSD对ECC纠 ...
- 数字梯形(cogs 738)
«问题描述:给定一个由n 行数字组成的数字梯形如下图所示.梯形的第一行有m 个数字.从梯形的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径.规则1:从梯形的顶 ...
- AtCoder Regular Contest 095E - Symmetric Grid
$n \leq 12,m \leq 12$,$n$行$m$列小写字母,现可做无数次操作:交换两行:交换两列.问是否有可能把他变成中心对称的. 没有去想分组枚举的复杂度QAQ 行和列的操作顺序是随意的. ...
- 标准C程序设计七---23
Linux应用 编程深入 语言编程 标准C程序设计七---经典C11程序设计 以下内容为阅读: <标准C程序设计>(第7版) 作者 ...