iOS多线程编程(四)------ GCD(Grand Central Dispatch)

Posted llguanli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS多线程编程(四)------ GCD(Grand Central Dispatch)相关的知识,希望对你有一定的参考价值。

一、简单介绍
是基于C语言开发的一套多线程开发机制。也是眼下苹果官方推荐的多线程开发方法。用起来也最简单。仅仅是它基于C语言开发,并不像NSOperation是面向对象的开发。而是全然面向过程的。假设使用GCD,全然由系统管理线程,我们不须要编写线程代码。仅仅需定义想要运行的任务,然后加入到适当的调度队列(dispatch_queue).GCD会负责创建线程和调度你的任务。系统会直接提供线程管理。

二、任务和队列
GCD中有两个核心概念
(1)任务:运行什么操作
(2)队列:用来存放任务
GCD的使用就两个步骤
(1)定制任务
(2)确定想做的事情
将任务加入到队列中,GCD会自己主动将队列中的任务取出,放到相应的线程中运行
提示:任务的取出遵循队列的FIFO原则:先进先出。后进后出

三、运行任务
1、GCD中有2个用来运行任务的函数
说明:把右边的參数(任务)提交给左边的參数(队列)进行运行
(1)用同步的方式运行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
參数说明:queue:队列; block:任务
(2)用异步的方式运行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

2、同步和异步的差别
同步:在当前线程中运行
异步:在还有一条线程中运行

四、队列
1、GCD的队列能够分为2大类型
(1)并发队列(Concurrent Dispatch Queue):能够让多个任务并发(同一时候)运行(自己主动开启多个线程同一时候运行任务)并发功能仅仅有在异步(dispatch_async)函数才有效

(2)串行队列(Serial Dispatch Queue):让任务一个接着一个地运行(一个任务运行完毕后,再运行下一个任务)

2、补充说明
有4个术语比較easy混淆:同步、异步、并发、串行(在博客 多线程编程(-)—-概念 也提到了)
同步和异步决定了要不要开启新的线程
同步:在当前线程中运行任务,不具备开启新线程的能力
异步:在新的线程中运行任务。具备开启新线程的能力
并发和串行决定了任务的运行方式
并发:多个任务并发运行
串行:一个任务运行完毕后,再运行下一个任务

五、(同步/异步)串行队列和(同步/异步)并发队列开启线程的总结 (代码演示样例)
说明:
(1)同步函数不具备开启线程的能力,不管是什么队列都不会开启线程;异步函数具备开启线程的能力,开启几条线程有队列决定(串行队列仅仅会开启一条新的线程,并发队列会开启多条线程)
(2) MRC下凡是函数中。各种函数名中带有create\\copy\\new\\retain等字眼。都须要在不须要使用这个数据的时候进行release
ARC下GCD的数据类型不须要再作release
CF(core Foundation)的数据在ARC环境下还是须要release
(3) 异步函数具备开线程的能力,但不一定会开线程

1、异步并发队列(同一时候开启N个线程)
这里写图片描写叙述

/**
 *  异步并发队列
 */
- (void)asynchronousConcurrent{
    NSLog(@"异步函数往并发队列中加入任务");
    NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);

    // 1、创建并发队列
    // 方法一 和创建串行队列一样
    //    dispatch_queue_t queue = dispatch_queue_create("asynConcurrent", DISPATCH_QUEUE_CONCURRENT);
    // 方法二 获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2、加入任务到队列
    dispatch_async(queue, ^{
        NSLog(@"下载图片1 ------ %@", [NSThread currentThread]);
        [self loadImage:1];
    });

    dispatch_async(queue, ^{
        NSLog(@"下载图片2------ %@", [NSThread currentThread]);
        [self loadImage:2];
    });

    dispatch_async(queue, ^{
        NSLog(@"下载图片3 ------ %@", [NSThread currentThread]);
        [self loadImage:3];
    });

    NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);


    // 打印结果 开启多个线程,并发运行。

没有先后顺序(有的话也是刚好巧合而已) 能够看number 能够看做线程值 /** 第一次运行 2016-08-24 12:53:24.026 YJGCDDemo[1220:24092] 异步函数往并发队列中加入任务 2016-08-24 12:53:24.027 YJGCDDemo[1220:24092] 主线程1111 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main} 2016-08-24 12:53:24.027 YJGCDDemo[1220:24092] 主线程2222 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main} 2016-08-24 12:53:24.027 YJGCDDemo[1220:24126] 下载图片1 ------ <NSThread: 0x7f81baf25e90>{number = 2, name = (null)} 2016-08-24 12:53:24.027 YJGCDDemo[1220:24128] 下载图片2------ <NSThread: 0x7f81bacc5fe0>{number = 3, name = (null)} 2016-08-24 12:53:24.027 YJGCDDemo[1220:24127] 下载图片3 ------ <NSThread: 0x7f81baf81ac0>{number = 4, name = (null)} 第二次运行 2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 异步函数往并发队列中加入任务 2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 主线程1111 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main} 2016-08-24 12:53:32.427 YJGCDDemo[1220:24092] 主线程2222 ---- <NSThread: 0x7f81bae04b90>{number = 1, name = main} 2016-08-24 12:53:32.427 YJGCDDemo[1220:24126] 下载图片2------ <NSThread: 0x7f81baf25e90>{number = 2, name = (null)} 2016-08-24 12:53:32.427 YJGCDDemo[1220:24260] 下载图片3 ------ <NSThread: 0x7f81baf7f660>{number = 7, name = (null)} 2016-08-24 12:53:32.427 YJGCDDemo[1220:24153] 下载图片1 ------ <NSThread: 0x7f81baf81ac0>{number = 6, name = (null)} */ }

2、异步串行队列(会开启线程,可是仅仅开启一个线程)
这里写图片描写叙述

/**
 *  异步串行队列
 */
- (void)asynchronousSerial{

    NSLog(@"用异步函数往串行队列中加入任务");
    NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);

    //1. 创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("asynSerial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"下载图片1 --- %@", [NSThread currentThread]);
        [self loadImage:1];
    });


    dispatch_async(queue, ^{
        NSLog(@"下载图片2 --- %@", [NSThread currentThread]);
        [self loadImage:2];
    });

    dispatch_async(queue, ^{
        NSLog(@"下载图片3 --- %@", [NSThread currentThread]);
        [self loadImage:3];
    });

    NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);


    // 打印结果:异步串行队列,会开启一个线程,顺序运行。 看运行结果也能够看出,图片是一张下载完在下载下一张的。

/** 2016-08-24 12:39:14.195 YJGCDDemo[942:16507] 用异步函数往串行队列中加入任务 2016-08-24 12:39:14.196 YJGCDDemo[942:16507] 主线程1111 ---- <NSThread: 0x7f8ed1f05f90>{number = 1, name = main} 2016-08-24 12:39:14.196 YJGCDDemo[942:16507] 主线程2222 ---- <NSThread: 0x7f8ed1f05f90>{number = 1, name = main} 2016-08-24 12:39:14.196 YJGCDDemo[942:16622] 下载图片1 --- <NSThread: 0x7f8ed1c43c00>{number = 2, name = (null)} 2016-08-24 12:39:14.261 YJGCDDemo[942:16622] 下载图片2 --- <NSThread: 0x7f8ed1c43c00>{number = 2, name = (null)} 2016-08-24 12:39:14.303 YJGCDDemo[942:16622] 下载图片3 --- <NSThread: 0x7f8ed1c43c00>{number = 2, name = (null)} */ }

3、同步并发队列(不会开启新的线程,并发队列失去并发的功能)
这里写图片描写叙述

/**
 *  同步并发队列
 */
- (void)synchronousConcurrent{
        NSLog(@"用同步函数往并发队列中加入任务");
        NSLog(@"主线程1111 ---- %@", [NSThread currentThread]);

        // 1.创建并发队列
        // 方式一 一般都使用这样的方式获取
    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        // 方式二 和创建串行队列一样
        dispatch_queue_t queue = dispatch_queue_create("syncConcurrentncy", DISPATCH_QUEUE_CONCURRENT);

        // 2.加添任务到队列
        dispatch_sync(queue, ^{
            NSLog(@"下载图片1 ---- %@", [NSThread currentThread]);
            [self loadImage:1];
        });

        dispatch_sync(queue, ^{
            NSLog(@"下载图片2 ---- %@", [NSThread currentThread]);
            [self loadImage:2];
        });

        dispatch_sync(queue, ^{
            NSLog(@"下载图片3 ---- %@", [NSThread currentThread]);
            [self loadImage:3];
        });

        NSLog(@"主线程2222 ---- %@", [NSThread currentThread]);


    // 打印结果 和同步串行队列一样 这边并发队列效果失效,不会开启线程。
    /**
     2016-08-24 11:20:44.153 YJGCDDemo[43913:3002870] 用同步函数往并发队列中加入任务
     2016-08-24 11:20:44.154 YJGCDDemo[43913:3002870] 主线程1111 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
     2016-08-24 11:20:44.154 YJGCDDemo[43913:3002870] 下载图片1 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
     2016-08-24 11:20:44.433 YJGCDDemo[43913:3002870] 下载图片2 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
     2016-08-24 11:20:44.475 YJGCDDemo[43913:3002870] 下载图片3 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}
     2016-08-24 11:20:44.508 YJGCDDemo[43913:3002870] 主线程2222 ---- <NSThread: 0x7f8742604eb0>{number = 1, name = main}

     */
}

4、同步串行队列(不会开启新的线程)
这里写图片描写叙述

/**
 *  同步串行队列
 */
- (void)synchronousSerial{
    NSLog(@"用同步函数往串行队列中加入任务");
    NSLog(@"主线程111----- %@", [NSThread currentThread]);

    // 1、创建串行队列 // DISPATCH_QUEUE_SERIAL 串行队列 也能够为NULL NULL时 默认是 串行队列; DISPATCH_QUEUE_CONCURRENT 并发队列
    dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL);

    // 2、加入任务到队列中运行
    dispatch_sync(queue, ^{
        // 此块代码没有不论什么意义,仅仅是为了体现同步串行队列的效果, 仅仅能运行完了 才干运行面下的。
        for (int i = 0; i < 30000; i++) {
            //
            NSLog(@"%i", i);
        }
        NSLog(@"下载图片1 ---- %@", [NSThread currentThread]);
        [self loadImage:1];
    });

    dispatch_sync(queue, ^{
        for (int i = 0; i < 30000; i++) {
            //
            NSLog(@"%i", i);
        }
        NSLog(@"下载图片2 -- %@", [NSThread currentThread]);
        [self loadImage:2];
    });

    dispatch_sync(queue, ^{
        for (int i = 0; i < 30000; i++) {
            //
            NSLog(@"%i", i);
        }
        NSLog(@"下载图片3 -- %@", [NSThread currentThread]);
        [self loadImage:3];
    });

    NSLog(@"主线程222----- %@", [NSThread currentThread]);


    // 打印结果就是同步按顺序运行。

每一个任务按顺序运行,不开启线程 /** 2016-08-24 10:52:55.049 YJGCDDemo[43413:2986818] 用同步函数往串行队列中加入任务 2016-08-24 10:52:55.049 YJGCDDemo[43413:2986818] 主线程111----- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main} 2016-08-24 10:52:55.050 YJGCDDemo[43413:2986818] 下载图片1 ---- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main} 2016-08-24 10:52:55.580 YJGCDDemo[43413:2986818] 下载图片2 -- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main} 2016-08-24 10:52:55.616 YJGCDDemo[43413:2986818] 下载图片3 -- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main} 2016-08-24 10:52:55.644 YJGCDDemo[43413:2986818] 主线程222----- <NSThread: 0x7fd5dbc00dd0>{number = 1, name = main} */ }

六、经常用法 在Demo中的CommonMethodsViewCotroller类

1、后台运行

 dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // something
    });

2、主线程运行

dispatch_async(dispatch_get_main_queue(), ^{
        // something
    });

3、一次性运行 dispatch_once()

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // code to be execution once
        NSLog(@"改行代码仅仅运行一次");
    });

4、延迟N秒运行 (这边列举了四种方式) dispatch_time()
这里写图片描写叙述

    NSLog(@"打印线程----- %@", [NSThread currentThread]);
    // 延时运行方式一 使用NSObject的方法
    // 2秒后再调用self的run方法
//    [self performSelector:@selector(loadImage) withObject:nil afterDelay:2.0];

    // 延迟运行方式二 使用GCD函数
       // 在同步函数中运行
        // 注意 假设使用异步函数 dispatch_async 那么[self performSelector:@selector(loadImage) withObject:nil afterDelay:5.0]; 不会被运行
//    dispatch_queue_t queue = dispatch_queue_create("yangjian.net.cn", 0);
//    dispatch_sync(queue, ^{
//        [self performSelector:@selector(loadImage) withObject:nil afterDelay:2.0];
//    });

    // 延迟运行方式三 能够安排其线程---> 主队列
//    dispatch_queue_t queue = dispatch_get_main_queue();
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{
//        NSLog(@"主队列--延迟运行------%@",[NSThread currentThread]);
//        [self gcdLoadImage];
//    });

    // 延迟运行方式四 能够安排其线程---> 并发队列
    //1、获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //2、计算任务运行的时间
    dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
    //3、会在when这个时间点。运行queue中的这个任务
    dispatch_after(when, queue, ^{
        NSLog(@"并发队列--延迟运行 ---- %@", [NSThread currentThread]);
        [self gcdLoadImage];
    });

5、运行某个代码片段N次 dispatch_apply()

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(4, globalQueue, ^(size_t index) {
        // 运行4次
    });

6、队列组的使用 dispatch_group_async()

    // 需求
    //1  分别异步运行2个耗时的操作
    //2  等两个异步操作都运行完毕后,再回到主线程运行操作

//   假设想要高速高效地实现上述需求,能够考虑用队列组

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        // 并发运行的线程一
    });

    dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
        // 并发运行的线程二
    });

    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        // 等前面的异步操作都运行完毕后,回到主线程
    });

6、dispatch_barrier_async()

/**
 *   使用此方法创建的任务首先会查看队列中有没有别的任务要运行。假设有。则会等待已有任务运行完毕再运行;同一时候在此方法后加入的任务必须等待此方法中任务运行后才干运行。(利用这种方法能够控制运行顺序,比如前面先载入最后一张图片的需求就能够先使用这种方法将最后一张图片载入的操作加入到队列,然后调用dispatch_async()加入其它图片载入任务)
 */
- (void)barrier{
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_queue_t queue = dispatch_queue_create("RICHARD", DISPATCH_QUEUE_CONCURRENT); // 创建并发队列

    dispatch_async(queue, ^{
        NSLog(@"下载图片1 --- %@", [NSThread currentThread]);
        UIImage *image = [self requestImageData:@"http://atth.eduu.com/album/201203/12/1475134_1331559643qMzc.jpg"];

        // 回到主线程
        dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
        dispatch_async(mainQueue1, ^{
            self.imageViewOne.image = image;
        });
    });

    dispatch_async(queue, ^{
        NSLog(@"下载图片2 --- %@", [NSThread currentThread]);
    });

    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async 下载图片3  --- %@", [NSThread currentThread]);
        UIImage *image = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
        dispatch_async(main_queue, ^{
            self.imageViewThree.image = image;
        });
    });



    dispatch_async(queue, ^{
        NSLog(@"下载图片4 --- %@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"下载图片5 --- %@", [NSThread currentThread]);
        UIImage *image = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
        dispatch_async(main_queue, ^{
            self.imageViewTwo.image = image;
        });
    });


    // 打印结果分析:1、 12 运行玩完 运行3  再运行45  2、 12顺序不定 45顺序不定
    /**
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367515] 下载图片2 --- <NSThread: 0x7ff720f13ac0>{number = 47, name = (null)}
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367518] 下载图片1 --- <NSThread: 0x7ff720e1c5d0>{number = 48, name = (null)}
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367102] dispatch_barrier_async 下载图片3  --- <NSThread: 0x7ff720d9b7d0>{number = 43, name = (null)}
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367293] 下载图片4 --- <NSThread: 0x7ff720c9e250>{number = 45, name = (null)}
     2016-08-25 10:47:00.560 YJGCDDemo[4436:367516] 下载图片5 --- <NSThread: 0x7ff720dba290>{number = 46, name = (null)}

     */



}

七、代码演示样例 在Demo中的CommonMethodsViewCotroller类
下载两张照片完后,合并照片。

(两种方式)
这里写图片描写叙述

/**
 *  合并图片(方式一)
 */
- (void)mergeImage{

//    // 获取全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//
//    // 获取主队列
//    dispatch_queue_t mainQueue = dispatch_get_main_queue();


    dispatch_async(global_queue, ^{
        // 下载图片1
        UIImage *image1 = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
        NSLog(@"图片1下载完毕----%@", [NSThread currentThread]);

        UIImage *image2 = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];

        NSLog(@"图片2下载完毕----%@", [NSThread currentThread]);

        // 回到主线程显示图片
        dispatch_async(main_queue, ^{
            NSLog(@"显示图片---%@", [NSThread currentThread]);
            self.imageViewOne.image = image1;
            self.imageViewTwo.image = image2;

            // 合并两张图片
            UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
            [image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];
            [image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];
            self.imageViewThree.image = UIGraphicsGetImageFromCurrentImageContext();
            // 关闭上下文
            UIGraphicsEndImageContext();

            NSLog(@"图片合并完毕----%@", [NSThread currentThread]);

        });
    });

    // 打印结果 须要等图片1下载完 在下载图片2 再回到主线程
    /**
     2016-08-24 16:58:40.123 YJGCDDemo[3480:125975] 图片1下载完毕----<NSThread: 0x7ff65acd85f0>{number = 3, name = (null)}
     2016-08-24 16:58:40.319 YJGCDDemo[3480:125975] 图片2下载完毕----<NSThread: 0x7ff65acd85f0>{number = 3, name = (null)}
     2016-08-24 16:58:40.319 YJGCDDemo[3480:125910] 显示图片---<NSThread: 0x7ff65ad00dd0>{number = 1, name = main}
     2016-08-24 16:58:40.335 YJGCDDemo[3480:125910] 图片合并完毕----<NSThread: 0x7ff65ad00dd0>{number = 1, name = main}
     */
    // 效率不高 须要等图片1,图片2都下载完了后才合并
    // 优化 使用队列组能够让图片1 图片2的下载任务同事进行,且当两个下载任务都完毕的时候回到主线程进行显示。


}
/**
 *  使用队列组解决(方式二)
 */
- (void)groupMergeImage{
    //步骤
    //  1、创建一个队列组
    //  2、开启一个任务下载图片1
    //  3、开启一个任务下载图片2
    //  同一时候运行下载图片1  和 下载图片2操作
    //  4、等group中的全部任务都运行完毕,再回到主线程运行其它操作

    // 1、创建一个队列租
    dispatch_group_t group = dispatch_group_create();

    // 2、开启一个任务下载图片1
    __block UIImage *image1 = nil;
    dispatch_group_async(group, global_queue, ^{
        image1 = [self requestImageData:@"http://h.hiphotos.baidu.com/image/pic/item/dc54564e9258d109a4d1165ad558ccbf6c814d23.jpg"];
        NSLog(@"图片1下载完毕--- %@", [NSThread currentThread]);
    });

    // 3、开启一个任务下载图片2
    __block UIImage *image2 = nil;
    dispatch_group_async(group, global_queue, ^{
        image2 = [self requestImageData:@"http://5.26923.com/download/pic/000/335/06efd7b7d40328f1470d4fd99a214243.jpg"];
        NSLog(@"图片2下载完毕--- %@", [NSThread currentThread]);
    });

    // 同一时候运行下载图片1\\下载图片2操作

    // 4、等group重的全部任务都运行完毕,再回到主线程运行其它操作
    dispatch_group_notify(group, main_queue, ^{
        NSLog(@"显示图 --- %@", [NSThread currentThread]);
        self.imageViewOne.image = image1;
        self.imageViewTwo.image = image2;

        // 合并两张图片
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
        [image1 drawAsPatternInRect:CGRectMake(0, 0, 100, 200)];
        [image2 drawAsPatternInRect:CGRectMake(100, 0, 100, 200)];
        self.imageViewThree.image = UIGraphicsGetImageFromCurrentImageContext();
        // 关闭上下文
        UIGraphicsEndImageContext();

        NSLog(@"图片合并完毕 --- %@", [NSThread currentThread]);
    });


    // 同一时候开启两个线程 分别下载图片 会比上面的效率高一点
    /**
     2016-08-24 16:58:03.785 YJGCDDemo[3467:125346] 图片1下载完毕--- <NSThread: 0x7f8d13cc61c0>{number = 3, name = (null)}
     2016-08-24 16:58:03.978 YJGCDDemo[3467:125349] 图片2下载完毕--- <NSThread: 0x7f8d13ece620>{number = 4, name = (null)}
     2016-08-24 16:58:03.978 YJGCDDemo[3467:125303] 显示图 --- <NSThread: 0x7f8d13e052b0>{number = 1, name = main}
     2016-08-24 16:58:03.995 YJGCDDemo[3467:125303] 图片合并完毕 --- <NSThread: 0x7f8d13e052b0>{number = 1, name = main}

     */

}

八、线程间通信

// 从子线程回到主线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
     // 运行耗时的异步操作
     dispatch_async(dispatch_get_main_queue(), ^{
          //回到主线程,运行UI刷新操作
     });
 });

九、Operation和GCD的对照
长处: 不须要关心线程管理。数据同步的问题;
差别:
1、性能:GCD更接近底层。而NSOperation则更高级抽象,所以GCD在追求性能的底层操作来说。是速度最快的。
2、从异步操作之间的事务性,顺序行,依赖关系。GCD须要自己写很多其它的代码来实现,而NSOperationQueue已经内建了这些支持
3、假设异步操作的国学很多其它的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。

底层代码中。任务之间不太互相依赖。而须要更高的并发能力,GCD则更有优势

十、总结
学了两天,对gcd有一些的了解。能在项目中使用多线程。只是这边也要避免非常多死锁的问题,后期有时间再整理出来。四天左右把ios多线程的几种方法都整理了下,写了demo。也算对自己的一个小小总结。


总结两点:
1、线程运行方式
dispatch_async 异步运行
dispatch_sync 同步运行
dispatch_delay 延迟运行
2、处理任务对象
dispatch_get_main_queue 主线程队列(UI线程队列)
dispatch_get_global_queue 并发线程队列
串行队列

demo地址: http://download.csdn.net/detail/yj229201093/9611939
參考链接:http://www.cnblogs.com/wendingding/p/3806821.html
感谢各路大神的博客,学无止境…

以上是关于iOS多线程编程(四)------ GCD(Grand Central Dispatch)的主要内容,如果未能解决你的问题,请参考以下文章

iOS/MacOS多线程编程GCD

《Objective-C 高级编程》干货三部曲:GCD篇

iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

iOS多线程编程--GCD

GCD 多线程API编程笔记

iOS开发——多线程编程(GCD)