• iOS多线程之6.GCD的其他用法


    队列组

    让队列里的任务同时执行,当任务都执行完毕时,再以通知的形式告诉程序员。举例,同时下载两张图片,两张图片都下载完了,在合成成一张。
    代码:

    #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还有什么想知道的,可以留言,我知道的一定告诉。

  • 相关阅读:
    IPV6地址分类链路本地地址和全球单播地址
    文件组与表分区
    网络负载均衡
    debian 11中安装Mongodb4.4.14
    在Vim编辑器中查找选定文本
    nvm的下载安装
    nvm use时报错 exit status 1:一堆乱码,exit status 5
    axios请求本地文件404
    使用yarn启用项目,报错无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\yarn.ps1,因为在此系 统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
    【服务器数据恢复】RAID5无法识别的数据恢复案例
  • 原文地址:https://www.cnblogs.com/doujiangyoutiao/p/6032555.html
Copyright © 2020-2023  润新知