• iOS多线程之5.GCD的基本使用


      上一篇文章我对GCD的几个基本概念做了介绍,但是大家看完了可能觉得对理解GCD并没有什么卵用。其实会用GCD其实很简单,只要记住两条就可以了。

    1. 主队列里的任务必须在异步函数中执行。

    主队列里的任务如果在同步函数中执行,就会造成死锁。什么是死锁?容我举例来说明。
    代码

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 1.
        dispatch_queue_t queue = dispatch_get_main_queue();
        NSLog(@"开始执行%@",[NSThread currentThread]);
        // 2.
        dispatch_sync(queue, ^{
            NSLog(@"执行任务%@",[NSThread currentThread]);
        });
        // 3.
         NSLog(@"结束执行%@",[NSThread currentThread]);
    }
    

    日志
    2016-11-04 14:27:44.261 TTTTTTTTTT[12014:139481] 开始执行<NSThread: 0x60000007d140>{number = 1, name = main}
      看到没有,主队列里的任务没有执行,程序也没有往下执行,这就叫做死锁。那又为什么会发生死锁。主队列里的任务默认都在主线程中执行,程序都把主队列里的任务放在主线程的最后面。当程序执行到2时,会把任务1放在主线程的后面,等主线程里的任务都执行完了在执行。可是这是什么函数啊?这是同步函数啊,它会堵塞当前的线程,后面的任务会等任务1执行完再执行。所以他们又开始互相等待,永远不会往下执行了。

    任务1对其他任务说:你们快执行啊?你们执行完我才能执行!
    其他任务对任务1说:不行啊,你执行完我们才能执行。这是同步那个二货规定的。
    任务1和其他任务就开始了漫长的等待……

    2. 全局并发队列里的任务在异步函数中执行才能实现并发。

    代码

    // 点击屏幕开始下载图片
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        NSString *strURL1 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg";
        NSString *strURL2 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/0eb30f2442a7d9334f268ca9a84bd11372f00159.jpg";
        NSString *strURL3 = @"http://www.2liangli.com/uploads/allimg/141108/1-14110R12140136.png";
        //获取全局并发队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            NSLog(@"%@开始下载第一张图片",[NSThread currentThread]);
            UIImage *image = [self downloadImageWithURL:strURL1];
            // 主线程中更新UI
           dispatch_async(dispatch_get_main_queue(), ^{
               self.imageView1.image = image;
           });
        });
        dispatch_async(queue, ^{
            NSLog(@"%@开始下载第二张图片",[NSThread currentThread]);
            UIImage *image = [self downloadImageWithURL:strURL2];
            // 主线程中更新UI
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageView2.image = image;
            });
        });
        dispatch_async(queue, ^{
            NSLog(@"%@开始下载第三张图片",[NSThread currentThread]);
            UIImage *image = [self downloadImageWithURL:strURL3];
            // 主线程中更新UI
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageView3.image = image;
            });
        });
    
    }
    - (UIImage *)downloadImageWithURL : (NSString *)strURL {
        NSURL *url = [NSURL URLWithString:strURL];
        return [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
    }
    

    日志

    2016-11-04 14:32:23.532 TTTTTTTTTT[12195:142364] <NSThread: 0x608000261500>{number = 5, name = (null)}开始下载第三张图片
    2016-11-04 14:32:23.532 TTTTTTTTTT[12195:142365] <NSThread: 0x60000007fac0>{number = 3, name = (null)}开始下载第一张图片
    2016-11-04 14:32:23.532 TTTTTTTTTT[12195:142368] <NSThread: 0x608000261700>{number = 4, name = (null)}开始下载第二张图片
    

      我们发现程序创建了三条线程,每条线程都执行下载图片的任务,三张图片几乎是同时开始下载的。这就实现了并发,也没有堵塞主线程。最重要的一点,下载完的图片,一定要在主线程更新。

    如果有兴趣可以试试把并发队列里的任务放在同步函数中执行,我们就会发现三张图片的下载都是在主线程中进行的,图片好长时间才下载完。因为图片是一个一个下载的,而不像上面是同时开始下载。

    至于自定义队列,我就不讲了,因为和上面的原理差不多,而且用的地方也不多。并发队列系统已经提供了,我们就不要自己创建了。至于串行队列,我们运用多线程就是为了多任务同时进行,串行队列里的任务无论在同步函数还是异步函数中,都不可能同时进行。

    关于GCD还有很多其他的用处,我会在下一篇文章中讲!

  • 相关阅读:
    3.6
    2.26
    2.22
    出差记录(每日食谱)
    关于本博客的样式
    知乎搜索/(引擎)的故事
    【历史/对越自卫反击战】刘立华||我的战地笔记——陵园祭
    如何在Xpath路径中添加变量?如何将字符串传递给Xpath?
    阿里网盘搜索网站汇总
    经济学人下载
  • 原文地址:https://www.cnblogs.com/doujiangyoutiao/p/6030236.html
Copyright © 2020-2023  润新知