队列组
让队列里的任务同时执行,当任务都执行完毕时,再以通知的形式告诉程序员。举例,同时下载两张图片,两张图片都下载完了,在合成成一张。
代码:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView3;
@end
@implementation ViewController
// 点击屏幕开始下载图片
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 创建全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建队列组
dispatch_group_t group = dispatch_group_create();
__block UIImage *image1 = nil;
// 开启一个任务
dispatch_group_async(group, queue, ^{
NSLog(@"%@开始下载第一张图片",[NSThread currentThread]);
NSString *strURL1 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg";
image1 = [self downloadImageWithURL:strURL1];
});
// 开启一个任务
__block UIImage *image2 = nil;
dispatch_group_async(group, queue, ^{
NSLog(@"%@开始下载第二张图片",[NSThread currentThread]);
NSString *strURL2 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/0eb30f2442a7d9334f268ca9a84bd11372f00159.jpg";
image2 = [self downloadImageWithURL:strURL2];
});
// 同时执行下载图片1\下载图片2的操作
// 等group里的任务执行完毕,执行的操作
// 回到主线程显示图片
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"%@显示图片",[NSThread currentThread]);
self.imageView1.image = image1;
self.imageView2.image = image2;
// 合并两张图片图片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(100, 50), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 50, 50)];
[image2 drawInRect:CGRectMake(50, 0, 50, 50)];
self.imageView3.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
});
}
- (UIImage *)downloadImageWithURL : (NSString *)strURL {
NSURL *url = [NSURL URLWithString:strURL];
return [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
}
@end
日志
2016-11-05 09:03:49.300 TTTTTTTTTT[2543:26927] <NSThread: 0x7ba80500>{number = 3, name = (null)}开始下载第一张图片
2016-11-05 09:03:49.301 TTTTTTTTTT[2543:28894] <NSThread: 0x7ba80b10>{number = 4, name = (null)}开始下载第二张图片
2016-11-05 09:03:49.453 TTTTTTTTTT[2543:26806] <NSThread: 0x79773680>{number = 1, name = main}显示图片
效果:
如果不用队列组,下载第一张图片、下载第二张图片、合并两张图片,就只能当做一个任务放入队列中,不能同时下载两张图片,耗时几乎多了一倍。因为,如果你不这样做(当做一个任务放入队列中),你不知道两张图片什么时候下载完,谁先下载完,因为每次都不确定,不知道什么时候合并图片。现在用group,由系统来帮我们监听两张图片下载的进度,咱们只要把两张图片都下载完的程序写写进dispatch_group_notify就好了。
延迟执行
延迟执行就是让程序过一会在执行某一段代码。用两种方法:- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay; dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
代码
- (void)viewDidLoad {
[super viewDidLoad];
// 第一种
[self performSelector:@selector(run) withObject:nil afterDelay:2];
// 第二种 可以安排执行的队列 3秒后执行
// 主队列
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"当前线程2%@",[NSThread currentThread]);
NSLog(@"GCD主队列过一会执行我");
});
// 全局并发队列
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(@"当前线程3%@",[NSThread currentThread]);
NSLog(@"GCD全局并发队列过一会执行我");
});
}
- (void)run {
NSLog(@"当前线程1%@",[NSThread currentThread]);
NSLog(@"过一会执行我");
}
日志
2016-11-05 09:27:04.903 TTTTTTTTTT[3439:39246] 当前线程1<NSThread: 0x7b6629a0>{number = 1, name = main}
2016-11-05 09:27:04.903 TTTTTTTTTT[3439:39246] 过一会执行我
2016-11-05 09:27:06.176 TTTTTTTTTT[3439:39246] 当前线程2<NSThread: 0x7b6629a0>{number = 1, name = main}
2016-11-05 09:27:06.176 TTTTTTTTTT[3439:39291] 当前线程3<NSThread: 0x7d175a90>{number = 3, name = (null)}
2016-11-05 09:27:06.177 TTTTTTTTTT[3439:39246] GCD主队列过一会执行我
2016-11-05 09:27:06.177 TTTTTTTTTT[3439:39291] GCD全局并发队列过一会执行我
延迟执行我们常用的可能是第一种方法。从那个线程中调用“ performSelector”,run方法就在哪个线程中执行可,一般是主线程。第二种方法是可以自定义方法执行的队列,可以是主队列,也可以是全局队列。本人比较喜欢用block,所以喜欢第二种,因为都写在一起,增加了代码的可读性。
一次性代码
一次性代码主要是在单例中应用。
#import "Person.h"
@implementation Person
static Person *person;
// 1
- (instancetype)shareInstance1 {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
person = [[Person alloc] init];
});
return person;
}
// 2.
- (instancetype)shareInstace2 {
if (!person) {
person = [[Person alloc] init];
}
return person;
}
@end
dispatch_once里的代码在整个程序运行过程中就执行一次!!!所以你有这方面的需求,也可以用这个。
其实关于GCD,今天是最后一篇文章了,其实GCD还有很多地方我没有讲到,一方面是我水平有限,一方面是不常用。从下一篇开始,我就开始讲NSOperation了。例外,如果大家关于GCD还有什么想知道的,可以留言,我知道的一定告诉。