GCD(Grand Central Dispatch),是苹果提供的一个解决多线程开发的解决方案。GCD会自动管理线程的生命周期(创建线程,调度任务,销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时GCD使用block来进行任务的执行,用起来非常方便、灵活。本篇博客我们主要将GCD,其他的多线程实现方式还有NSThread、NSOperationQueue,我们将会在以后的博客中讲解。
这里我们要提到一个概念:【任务】。就是操作,就是你要执行的一段代码,在GCD中就是一个Block,所以添加任务十分方便。
【同步执行】:只要是同步执行的任务,都会在当前线程执行,不会另开线程。所以说网络请求等耗时操作一般不使用同步,而是异步,否则会阻塞主线程,界面会卡住。
【异步执行】:只要是异步任务执行的任务,都会另开线程,在别的线程执行。
同步(sync)和异步(async)的主要区别在于会不会阻塞当前线程,直到Block中的任务执行完毕。
如果是同步(sync)操作,它会阻塞当前线程并等待Block中的任务执行完毕,然后当前线程才会继续往下运行(因为同步操作没有开新线程,是在主线程中执行的,所以会阻塞)。
如果是异步(async)操作,当前线程会直接往下执行,他不会阻塞当前线程(因为异步操作是在另一个线程中执行的,所以不会阻塞主线程)。
队列:用于存放任务,一共有两种队列:串行队列和并行队列。
1.串行队列(private dispatch queue)一次只执行一个线程,按照添加到队列的顺序依次执行;
2.并行队列(global dispatch queue)一次可以执行多个线程,线程的执行没有先后顺序。根据同步或者异步有不同的执行方式。放到并行队列的任务,GCD也会FIFO的取出来,但不同的是,他取出来一个就会放到别的线程,然后再取出来一个又放到另一个线程。
3.Main dispatch queue:UI界面所在的线程队列是主线程。
下面我对上述几个案例进行代码示例:项目已经上传至github: https://github.com/chenyufeng1991/GCD 。中的GCD1项目。
【串行队列示例】
(1)首先导入GCD封装后的代码,可以从我的项目中直接复制,总共9个文件:其实个人推荐使用iOS原生的GCD,请移步《iOS开发——GCD的使用与多线程开发浅析》这篇博客。
(2)ViewController中的实现如下:
#import "ViewController.h"
#import "GCD.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//执行串行队列;
[self serailQueue];
}
//串行队列;
- (void)serailQueue{
//创建出队列;
GCDQueue *queue = [[GCDQueue alloc] initSerial];
//执行队列中的线程;
[queue execute:^{
NSLog(@"1");
}];
[queue execute:^{
NSLog(@"2");
}];
[queue execute:^{
NSLog(@"3");
}];
[queue execute:^{
NSLog(@"4");
}];
[queue execute:^{
NSLog(@"5");
}];
}
@end
(4)结果分析
输出结果和我们的预期一样,是按照添加到队列的顺序执行的。
【并行队列示例】
(1)同样需要引入GCD源代码,在ViewController中的实现如下:
#import "ViewController.h"
#import "GCD.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//执行并发队列;
[self concurrent];
}
//并发队列;
- (void)concurrent{
//创建出队列;
GCDQueue *queue = [[GCDQueue alloc] initConcurrent];
//执行队列中的线程;
[queue execute:^{
NSLog(@"1");
}];
[queue execute:^{
NSLog(@"2");
}];
[queue execute:^{
NSLog(@"3");
}];
[queue execute:^{
NSLog(@"4");
}];
[queue execute:^{
NSLog(@"5");
}];
}
@end
(2)结果输出:
(3)结果分析:
输出结果和我们预期的一样,执行的顺序是无序的。
【UI界面更新】
(1)使用GCD,我们可以来进行网络操作或者下载请求,然后更新UI。这一系列操作是串行操作,需要有一定的顺序。在这里我使用了同步请求。在ViewController中实现如下:
#import "ViewController.h"
#import "GCD.h"
@interface ViewController ()
@property(strong,nonatomic) UIImage *image;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//globalqueue其实就是并行队列。
[GCDQueue executeInGlobalQueue:^{
//处理业务逻辑
NSString *url = @"http://imgsrc.baidu.com/forum/w%3D580/sign=2e824145d2c8a786be2a4a065708c9c7/5a8e72094b36acaf254077437fd98d1000e99c4a.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSData *picData = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:nil];
NSLog(@"处理业务逻辑");
//获取图片;
self.image = [UIImage imageWithData:picData];
[GCDQueue executeInMainQueue:^{
NSLog(@"更新UI");
//更新UI
[self.imageView setImage:self.image];
}];
}];
}
@end
github主页:https://github.com/chenyufeng1991 。欢迎大家访问!