GCD基础知识集合

GCD概念简单理解

GCD是基于C的Api。不需要自己管理线程生死。只需要创建队列,把任务放进队列里面就可以了。看上去很简单,其实也是有一段心酸路。
GCD有两个核心概念。一个是任务,一个是队列。

同步函数:在当前线程中执行,不开启新的线程
dispatch_sync(dispatch_queue_t queue, dispatch_block_tblock);

异步函数:具备开启线程的能力。
dispatch_async(dispatch_queue_t queue, dispatch_block_tblock);

队列

并发队列
自动开启多个线程,并且可以让多个任务同时执行。
仅仅在异步函数(dispatch_async)下有效。

串行队列
让线程一个接着一个的执行。一条线程执行完后再执行下一条线程。

并发队列

并发队列不需要手动创建。以下是创建代码。

dispatch_queue_tdispatch_get_global_queue(
dispatch_queue_priority_tpriority,// 队列的优先级
unsignedlongflags);// 此参数暂时无用,用0即可
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//获得全局并发队列

全局并发队列的优先级
#defineDISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#defineDISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#defineDISPATCH_QUEUE_PRIORITY_LOW (-2)// 低
#defineDISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
串行队列
使用dispatch_queue_create函数创建串行队列
dispatch_queue_t
dispatch_queue_create(constchar*label, //队列名称
dispatch_queue_attr_tattr);//队列属性,一般用NULL即可
dispatch_queue_tqueue = dispatch_queue_create("isQueue", NULL);//创建
dispatch_release(queue);//非ARC时候需要释放手动创建的队列

使用主队列(跟主线程相关联的队列)
主队列是GCD自带的一种特殊的串行队列
放在主队列中的任务,都会放到主线程中执行
使用dispatch_get_main_queue()获得主队列
dispatch_queue_tqueue = dispatch_get_main_queue();

使用dispatch_sync同步函数时候,在主线程中往主队列添加任务会造成死锁

队列与任务的结合
函数 全局并发队列 手动创建串行队列 主队列
同步 (sync) 没有开启新线程 串行执行任务 没有开启新线程 串行执行任务 没有开启新线程 串行执行任务
异步 (async) 有开启新线程 并发执行任务 有开启新线程 串行执行任务 没有开启新线程 串行执行任务
线程间的通讯

更新UI,数据等都是要回到主线程的。不能在子线程。

//获取全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

        NSLog(@"-子线程-- 开始下载图片--%@",[NSThread currentThread]);

        //下载数据是耗时操作放到子线程
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a94369f4cb1c178a82b9011442.jpg"]]];

            dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"-主线程-- 刷新UI--%@",[NSThread currentThread]);
            //回到主线程刷新UI
            self.imageView.image = image;
        });
    });
延时操作

延时操作不会堵塞当前线程.

//延迟操作
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)),//从什么时候开始,是一个固定的算法
                   dispatch_get_main_queue(),//队列
                   ^{
        //做要做的操作
    });
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#pragma mark 延迟操作创建一
    //获取全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //延时多久
    dispatch_time_t whenTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    
    //延时操作,根据whenTime设计的时间
    dispatch_after(whenTime, queue, ^{
        NSLog(@"倒计时结束");
        
        dispatch_async(queue, ^{
            NSLog(@"-子线程-- 开始下载图片--%@",[NSThread currentThread]);
            
            //下载数据是耗时操作放到子线程
            UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a94369f4cb1c178a82b9011442.jpg"]]];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"-主线程-- 刷新UI--%@",[NSThread currentThread]);
                
                //回到主线程刷新UI
                self.imageView.image = image;
                
            });
        });
    });
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
#pragma mark 延迟操作创建二
    //获取全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSLog(@"倒计时结束");
        
        dispatch_async(queue, ^{
            NSLog(@"-子线程-- 开始下载图片--%@",[NSThread currentThread]);
            
            //下载数据是耗时操作放到子线程
            UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/b219ebc4b74543a94369f4cb1c178a82b9011442.jpg"]]];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"-主线程-- 刷新UI--%@",[NSThread currentThread]);
                
                //回到主线程刷新UI
                self.imageView.image = image;
            });
        });
    });
GCD一次性代码
static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
            //代码只执行一次
    });
});
GCD队列组
分组模式 dispatch_group_notify

可以异步执行多个耗时操作。等耗时操作都执行完毕之后会回到主线程执行操作。主要用于监听任务是否完成。

//获取全局队列
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //创建一个队列组
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, globalQueue, ^{
        
        NSLog(@"--- 1 开始--- %@",[NSThread currentThread]);
        //延时5秒 模仿堵塞子线程
        [NSThread sleepForTimeInterval:5];
        NSLog(@"--- 2 --- 完成 %@",[NSThread currentThread]);
        
    });
    
    dispatch_group_async(group, globalQueue, ^{

        NSLog(@"--- 2 开始--- %@",[NSThread currentThread]);
        //延时5秒 模仿堵塞子线程
        [NSThread sleepForTimeInterval:5];
        NSLog(@"--- 2 --- 完成 %@",[NSThread currentThread]);
        
    });
    
    //在这个队列组里面,会等group中的全部代码执行完毕再去执行其它的操作
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        
        // 等前面的异步操作都执行完毕后,回到主线程...
        NSLog(@"全部完成");
        
    });

    //非ARC时候要释放掉
    //dispatch_release(group);
dispatch_apply组内无序循环执行任务
//循环执行任务,并且执行任务的顺序是无序列的。这里会堵塞当前的线程。所以要注意。一般都是在子线程中执行。
dispatch_apply(size_t iterations,//执行的次数
                   <#dispatch_queue_t queue#>,//队列
                   <#^(size_t)block#>)//任务
    dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
        NSLog(@"%zu",index);
    });
dispatch_set_target_queue 变更queue的优先级别
dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.queue", NULL);
    //设置这个全局并发队列的优先级为后台
    dispatch_queue_t globalQueued = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_set_target_queue(exampleQueue, globalQueued);
    /**
     *  经过转换之后exampleQueue的优先级别变成后台
     */
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容