上篇记录了GCD的各种基本使用方法及特点,下面是GCD在项目中的常用场景
1、创建单例 dispatch_once
static People *sharePeople = nil;
+ (instancetype)sharePeople{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"oncetoken");//这里的代码只会执行一次
sharePeople = [[self alloc]init];
});
return sharePeople;
}
2、延迟执行 dispatch_after (异步)
函数原型
参数 when 延迟执行的时间
参数 quene 在哪个队列中执行
参数 block 延迟执行的内容
dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
NSLog(@"开始");
double delayInSeconds = 2.0;
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, mainQueue, ^{
NSLog(@"延时执行的2秒");
});
NSLog(@"结束");
执行结果:
2016-12-27 15:37:32.509 GCD[1547:228385] 开始
2016-12-27 15:37:32.509 GCD[1547:228385] 结束
2016-12-27 15:37:34.510 GCD[1547:228385] 延时执行的2秒
注意:延迟执行在iOS中一般还可以通过下面的方法或者NSTimer来实现
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
但这个方法并不是安全的,因为这个方法或者是NSTimer都需要有一个runloop来实现,而只有主线程在创建的时候回默认自动运行一个runloop,普通的子线程是没有的,一旦这两种方式在子线程中调用,则延迟方法里面的内容就永远不会执行。
相对来说GCD是安全的
3、并发地执行循环迭代 dispatch_apply
代替for循环 要求,循环次数固定并且循环执行的次序无关,这是可以用dispatch_apply提高效率(并发执行)
原来的for循环
int i;
int count = 10;
for (i = 0; i < count; i++) {
printf("%d ",i);
}
这是输出
0 1 2 3 4 5 6 7 8 9
同dispatch_apply代替
// 获得全局并发queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
size_t count = 10;
dispatch_apply(count, queue, ^(size_t i) {
printf("%zd ", i);
});
可能就会输出
0 1 3 2 4 5 6 8 7 9
4、在子线程中调用下载图片等耗时操作,下载完成后在主线程刷新界面
// 异步下载图片
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:@"http://image.baidu.com/search/detail?ct=503316480&z=0&tn=baiduimagedetail&ipn=d&cl=2&cm=1&sc=0&lm=-1&ie=gbk&pn=0&rn=1&di=20652390440&ln=30&word=ͼƬ&os=3812566282,1648699000&cs=214931719,1608091472&objurl=http%3A%2F%2F4493bz.1985t.com%2Fuploads%2Fallimg%2F150127%2F4-15012G52133.jpg&bdtype=0&simid=3354004378,369260611&pi=0&adpicid=0&fr=ala&ala=1&alatpl=others&pos=1"];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
// 回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});
这里可能会有这种情况,某界面需要两张或多张图片,当所有的图片加载完成后才刷新界面,这时可以用 Dispatch Group来实现
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 异步下载图片
dispatch_async(queue, ^{
// 创建一个组
dispatch_group_t group = dispatch_group_create();
__block UIImage *image1 = nil;
__block UIImage *image2 = nil;
// 关联一个任务到group
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下载第一张图片
NSString *url1 = @"http://car0.autoimg.cn/upload/spec/9579/u_20120110174805627264.jpg";
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url1]]];
});
// 关联一个任务到group
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下载第一张图片
NSString *url2 = @"http://hiphotos.baidu.com/lvpics/pic/item/3a86813d1fa41768bba16746.jpg";
image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url2]]];
});
// 等待组中的任务执行完毕,回到主线程执行block回调
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
self.imageView1.image = image1;
self.imageView2.image = image2;
// 千万不要在异步线程中自动释放UIImage,因为当异步线程结束,异步线程的自动释放池也会被销毁,那么UIImage也会被销毁
});
});