标签:
它是一种纯C语言,它是为多核并列运算设计的。可以自动管理线程的生命周期。
GCD 是面向任务和队列的,不是面向线程的。他有两个关键字“任务”“队列”。
使用 GCD 的步骤主要是:
1 定制任务
2 任务添加到队列中,队列支持 FIFO 原则
dispath_queue_t queue = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFULT,0);
dispath_async(queue,^{
//任务代码段
});
在当前线程中执行,不具备开启线程的能力。
dispath_sync( queue,block); //在队列中执行 block 所定义的任务,以同步的方式
在新线程中执行,具备开启新线程的能力
dispath_async(queue,block); //在队列中执行 block 所定义的任务,以异步的方式
决定了是否有能力开启新的线程
并行队列,队列中的任务,以并行的方式进行,多任务同时进行。
一般情况下,我们使用的是全局的并发队列。获取全局并发队列的方式如下:
//默认的写法,获取全局并发队列。前一个参数是优先级默认,后面一个参数是苹果保留的参数
dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
串行队列中,队列中的人物,都是以串行的方式进行。先执行一个任务,再执行另一个任务。
串行队列分为两种,一种是手动创建的串行队列,另一个是主队列
//默认写法,第一个参数是队列名称,随便填写;第二个参数是队列属性,一般情况下写 NULL
dispatch_queue_create("queueName",NULL);
//默认写法
dispath_get_main_queue();
主队列的任务执行,都是在主线程中进行的,一般用来做线程间的通信。
①会创建新的线程
②并发执行任务
下面的例子中,任务1和任务2是并发执行的
//实例代码
//①获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//②异步方式处理任务1
dispatch_async(queue,^{
NSLog("下载图片1--%@",[NSThread currentThread]);
});
//②异步方式处理任务2
dispatch_async(queue,^{
NSLog("下载图片2--%@",[NSThread currentThread]);
});
①会创建新线程,因为是串行方式执行,一般情况下只会新建一条线程。
②队列中的任务以串行方式执行:任务1和任务2是串行执行的
//示例代码
//①手动创建串行队列
dispatch_queue_t queue = dispatch_queue_create("queueName",NULL);
//②异步方式处理任务1
dispatch_async(queue,^{
NSLog("正在下载图片1---%@",[NSThread currentThread]);
});
//②异步方式处理任务2
dispatch_async(queue,^{
NSLog("正在下载图片2---%@",[NSThread currentThread]);
});
①不会创建线程
②并发队列的并发功能消失,队列中的所有任务串行执行。
//示例代码
//①获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//②同步执行任务1
dispatch_sync(queue,^{
NSLog(@"下载图片1---%@",[NSThread currentThread]);
});
//②同步执行任务2
dispatch_sync(queue,^{
NSLog(@"下载图片2---%@",[NSThread currentThread]);
});
①不会创建新线程
②串行队列中的所有任务串行执行
//示例代码
//①手动创建串行队列
dispatch_queue_t queue = dispatch_queue_create("queueName",NULL);
//②同步执行任务1
dispatch_sync(queue,^{
NSLog(@"正在下载图片1-----%@",[]NSThread currentThread]);
});
//②同步执行任务2
dispatch_sync(queue,^{
NSLog(@"正在下载图片2-----%@",[]NSThread currentThread]);
});
①主队列是特殊的队列,此时异步方式虽然具备创建新线程的能力,但是实际上并不能创建新线程
②所有的任务都是在主队列中串行执行的,也就是在主线程中进行,一般用来做进程之间的通信。
//①获取当前的主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//②异步方式执行
dispatch_async(queue,^{
NSLog(@"正在下载图片---%@",[NSThread currentThread]);
});
当前执行下面的程序是在主线程中执行的,当执行到第二步的时候,需要将下面的任务加入到主队列中串行执行。因为是串行执行,主线程必须等到第二步结束后才能继续向下执行,但是第二步是将任务加载到了主队列的末尾,必须要等到之前主线程队列执行完毕后才能执行,所以陷入了卡死状态。
//1获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2同步执行主队列
dispatch_sync(queue,^{
NSLog(@"正在执行。。。");
});
需要遵循的原则:
* 凡是函数名中带有 create\copy\new\retain 等字眼,都应该在不需要使用这个数据的时候release 操作
* GCD的数据类型,在ARC下不需要再 release
* CF(Core Foundation)的数据类型在 ARC 和 MRC 环境下都需要手动 release。
例子:
* CFRelease(id);
NSDictionary *dict = @{@"1":@"1"};
CFDictionaryRef dictCF = (__bridge CFDictionaryRef)(dict);
CFRelease(dictCF);
举例,点击控制器的 View,在子线程中从网上下载一张图片,下载完毕后在主线程中更新按钮的图片。
//1 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//2 异步方式下载图片
dispatch_async(queue, ^{
NSString *str = @"http://u1.img.mobile.sina.cn/public/files/image/600x150_img577f313ec621a.png";
NSURL *url = [NSURL URLWithString:str];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//3 回到主线程,给 UIButton 设置图片
dispatch_async(dispatch_get_main_queue(), ^{
[self.button setImage:image forState:UIControlStateNormal];
});
});
在程序设计中,延时执行的方式有三种
想要做延时操作,此种方式只需要在延时执行的操作之前执行如下代码即可
//使当前线程睡眠3秒钟后再次执行
[NSThread sleepForTimeInterval:3]
缺点:会卡死当前调用的线程,整个线程会停滞。如果卡死的是主线程,那么意味着 UI 会受很大的影响。
//当3秒后,执行 download 方法。3秒后在主线程中执行该操作
[self performSelector:@selector(download) withObject:nil afterDelay:3]
可以根据队列的类型,决定延时后的操作在哪个线程中执行,可以指定在全局并发队列中执行,也可以指定在主队列中执行。
//dispatch_queue_t queue = dispatch_get_main_queue();
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(@"延时操作---%@",[NSThread currentThread]);
});
某个代码段,在程序运行过程中,不管调用多少次,实际上改代码只执行了一次,这就是一次性代码
比如说:点击界面后,开始下载图片。如果下载图片的代码不是一次性代码的话,每点击一次界面,都需要再次下载,显然不符合实际情况。使用其他方式也可以实现(定义变量或者定义标识),但一次性代码是最简单的操作。
static dispatch_once_t oneceToken;
dispatch_once(&onceToken,^{
//想要只执行一次的代码
//.....
});
队列组就是一个对象,内部包含了队列,当队列中的任务执行完毕后,会自动调用响应的方法,这就是队列组。
需要从网络上下载一张图片,然后再下载一张 logo 图片,用 logo 做水印。如果按照顺序,先下载图片,再下载 logo,最后进行图片水印叠加,会比较耗时。最好的办法是 两张图片分别放到两个线程中进行,当两个图片全部下载好之后,再进行组装。
采用队列组,手动创建一个队列组,使用dispatch_group_async(group,queue,^{})来开辟新线程执行下载操作。当队列组中的队列任务全部结束之后,会自动调用 dispatch_group_notify(queue,^{})函数,也就是说我们可以将合并水印的操作放在这个函数中进行。
//1 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY——DEFAULT,0);
//2 创建队列组--如果是 MRC 环境中,需要 release操作: dispatch_release(group);
dispatch_group_t group = dispatch_group_create();
//3 下载图片1
__block UIImage *image1 = nil; //加__block 修饰是为了 block 中可以访问该变量
dispatch_group_async(group,queue,^{
NSString *str = @"http://image1.png";
NSURL *url = [NSURL urlWithString:str];
NSData *data = [NSData dataWithContentsOfURL:url];
image1 = [UIImage imageWithData:data];
});
//4 下载图片2
__block UIImage *image2 = nil; //加__block 修饰是为了 block 中可以访问该变量
dispatch_group_async(group,queue,^{
NSString *str = @"http://image2.png";
NSURL *url = [NSURL urlWithString:str];
NSData *data = [NSData dataWithContentsOfURL:url];
image2 = [UIImage imageWithData:data];
});
//5 合并图片--group中所有队列的任务执行完之后,自动调用下面的函数
dispatch_group_notify(group,queue,^{
//5.1 开启当前图形上下文
UIGraphicsBeginImageContextWithOptions(image1.size,NO,0.0);
//5.2 将 image1画在上下文
[image1 drawInRect:CGRectMake(0,0,image1.size.width,image1..size.height)];
//5.3 将 image2画在上下文
[image2 drawInRect:CGRectMake(0,0,100.50)];
//5.4 获取当前上下文的图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//5.6 回到主线程,刷新 UI
dispatch_async(dispath_get_main_queue,^{
self.imageView.image = image;
});
});
标签:
原文地址:http://blog.csdn.net/smallyou113/article/details/51882683