IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习
介绍:前面内容源自网络
Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。
练习简介:点击ok按钮就会计算从1-很大的数的和,不用多线程就会出现假死状态,其他操作不能执行,现在用多线程解决这个问题
注意:(Dispatch queue启动时默认状态是挂起的,我们创建完毕之后得主动恢复,否则事件不会被传送)
设计:
GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行
dispatch queue分为下面三种:
Serial
又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
Concurrent
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
Main dispatch queue
它是全局可用的serial queue,它是在应用程序主线程上执行任务的。
我们看看dispatch queue如何使用
1、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- // 耗时的操作
- dispatch_async(dispatch_get_main_queue(), ^{
- // 更新界面
- });
- });
如果这样还不清晰的话,那我们还是用上两篇博客中的下载图片为例子,代码如下:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];
- NSData * data = [[NSData alloc]initWithContentsOfURL:url];
- UIImage *image = [[UIImage alloc]initWithData:data];
- if (data != nil) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.imageView.image = image;
- });
- }
- });
运行显示:

是不是代码比NSThread NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。
系统给每一个应用程序提供了三个concurrent dispatch queues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列,如下:
- dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
这里也用到了系统默认就有一个串行队列main_queue
- dispatch_queue_t mainQ = dispatch_get_main_queue();
虽然dispatch queue是引用计数的对象,但是以上两个都是全局的队列,不用retain或release。
2、dispatch_group_async的使用
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_group_t group = dispatch_group_create();
- dispatch_group_async(group, queue, ^{
- [NSThread sleepForTimeInterval:1];
- NSLog(@"group1");
- });
- dispatch_group_async(group, queue, ^{
- [NSThread sleepForTimeInterval:2];
- NSLog(@"group2");
- });
- dispatch_group_async(group, queue, ^{
- [NSThread sleepForTimeInterval:3];
- NSLog(@"group3");
- });
- dispatch_group_notify(group, dispatch_get_main_queue(), ^{
- NSLog(@"updateUi");
- });
- dispatch_release(group);
dispatch_group_async是异步的方法,运行后可以看到打印结果:
2012-09-25 16:04:16.737 gcdTest[43328:11303] group1
2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2
2012-09-25 16:04:18.738 gcdTest[43328:13003] group3
2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi
每个一秒打印一个,当第三个任务执行后,upadteUi被打印。
这个group如此写是无法显示ui 的,以下是解决方案
- (IBAction)onClickDispatchCancel:(id)sender {
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(self.gcd_group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"yes";
});
});
dispatch_group_async(self.gcd_group, queue, ^{
[NSThread sleepForTimeInterval:1];
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"hello";
});
});
dispatch_group_async(self.gcd_group, queue, ^{
[NSThread sleepForTimeInterval:2];
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"ok";
});
});
dispatch_group_notify(self.gcd_group, queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@"finished";
});
});
}
每一个里面都加上了dispatch_async(dispatch_get_main_queue(),只有在主线程里才会更新ui的显示.这里我遇到过一个崩溃,而且xcode不给提示原因是最后一句我写成了 dispatch_group_notify(self.gcd_group, queue, ^{
self.textField.text=@"finished";
});
所以不仅不显示,而且结果是程序崩溃.所以显示ui更新的时候就要进入主线程.
3、dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:
- dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);
- dispatch_async(queue, ^{
- [NSThread sleepForTimeInterval:2];
- NSLog(@"dispatch_async1");
- });
- dispatch_async(queue, ^{
- [NSThread sleepForTimeInterval:4];
- NSLog(@"dispatch_async2");
- });
- dispatch_barrier_async(queue, ^{
- NSLog(@"dispatch_barrier_async");
- [NSThread sleepForTimeInterval:4];
- });
- dispatch_async(queue, ^{
- [NSThread sleepForTimeInterval:1];
- NSLog(@"dispatch_async3");
- });
打印结果:
2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async
2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3
请注意执行的时间,可以看到执行的顺序如上所述。
4、dispatch_apply
执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
// 执行5次
});
//练习:
一,界面设计,两个按钮一个文本框
1,声明线程属性:@property (nonatomic,strong) NSThread *thread;
2,重写get方法:
-(NSThread *)thread
{
if (_thread!=nil) {
return _thread;
}
_thread=[[NSThread alloc] initWithTarget:self selector:@selector(threadMethod) object:nil];
return _thread;
}
3,实现部分
-(void)threadMethod
{
long long sum=self.textView.text.longLongValue;
for (long long i=0; i<=45000; i++) {
if ([self.thread isCancelled]) {//如果线程是取消状态就要把线程销毁,否则再次执行的时候会崩溃
self.thread=Nil;//释放内存
[NSThread exit];//销毁线程
}
[self performSelectorOnMainThread:@selector(refresh:) withObject:@(sum).description waitUntilDone:YES];
sum+=i;
}
self.thread = nil;//这地方如果不销毁线程,当程序计算执行完之后再次点击ok按钮就会出现程序崩溃
}
-(void)refresh:(id)sender
{
self.textView.text=sender;
NSLog(@"refresh");
}
- (IBAction)onClickStart:(id)sender {
if ([self.thread isExecuting]) {//如果程序正在执行就直接返回,否则会出错
return;
}
// NSLog(@"%@",[NSThread currentThread]);
[self.thread start];
}
- (IBAction)onClickCancel:(id)sender {
if ([self.thread isExecuting]) {//如果程序正在执行就执行取消操作,如果没有这个判断,结果是:点击两次取消按钮,在点击ok按钮就会崩溃
[self.thread cancel];
}
}
2,用NSOperationQueue方式来实现
- (IBAction)onClickOperationBegin:(id)sender {
if (self.queue.operationCount>=1)
{
return;
}
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(queueMethod) object:nil];
[self.queue addOperation:operation];
[self.queue setSuspended:NO];
}
- (IBAction)onClickOperationCancel:(id)sender {
[self.queue setSuspended:YES];
}
-(void)queueMethod
{
long long sum=self.textField.text.longLongValue;
for (long long i=0; i<23453; i++) {
if ([self.queue isSuspended]) {
return;
}
[self performSelectorOnMainThread:@selector(refreshThread:) withObject:@(sum).description waitUntilDone:YES];
sum+=i;
}
[self.queue setSuspended:YES];
}
3,dispatch方式的实现(停止功能没实现,欢迎供稿)
- (IBAction)onClickDispatchBegin:(id)sender {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
usleep(200);
long long sum=self.textField.text.longLongValue;
for (long long i=0; i<35457; i++)
{
usleep(200);
dispatch_async(dispatch_get_main_queue(), ^{
self.textField.text=@(sum).description;
});
sum+=i;
}
});
}
IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习的更多相关文章
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
http://blog.csdn.net/totogo2010/article/details/8016129 GCD很好的博文
- iOS 多线程编程之Grand Central Dispatch(GCD)
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...
- Grand Central Dispatch (GCD)
Grand Central Dispatch (GCD) Reference Grand Central Dispatch (GCD) comprises language features, run ...
- 深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
- [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
- iOS 中NSOperationQueue,Grand Central Dispatch , Thread的上下关系和区别
In OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central D ...
- iOS开发之再探多线程编程:Grand Central Dispatch详解
Swift3.0相关代码已在github上更新.之前关于iOS开发多线程的内容发布过一篇博客,其中介绍了NSThread.操作队列以及GCD,介绍的不够深入.今天就以GCD为主题来全面的总结一下GCD ...
- Grand Central Dispatch(GCD)详解(转)
概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...
随机推荐
- S2 第二章数据库的实现
实现增删改查代码 1 select * from student --增加数据 insert into student (name,banji,xuehao) values(,) --修改数据 upd ...
- java中汉字自动转换成拼音
java中汉字自动转换成拼音 1.需要下载jar包 pinyin4j.2.5.0.jar ,加入到WEB-INF下的lib里边,右键add to bulid path. 2.[代码]PinYinUti ...
- li排序的两种方法
1.一般做法 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...
- Octopus系列之关于多选属性如何在OO中表示呢?
在电子商务系统中 关于产品属性的问题 会设计如下几个表 产品信息 Product 选项信息表 Option 存储 Size Color.... 选项值信息表 O ...
- 表单form的属性,单行文本框、密码框、单选多选按钮
基础表单结构: <body> <h1> <hr /> <form action="" name="myFrom" en ...
- 深入理解Redis:底层数据结构
简介 redis[1]是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...
- Uploadify使用
Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.不过官方提供的实例时php版本的,本文将详细介绍Uploadify在Aspnet中的使用,您也可以点击下面的链接进行演示 ...
- [Jquery]瀑布流
$(window).load(function(e){ waterfall(); var dataInt={'data':[{'src':'1.jpg'},{'src':'2.jpg'}, ...
- http://bootswatch.com/
http://bootswatch.com/ http://v3.bootcss.com/examples/dashboard/
- struts2 ModelDriven 和 Preparable 拦截器
Struts2 运行流程图-1