GCD常用方法

gcd中常用的方法


一.dispath_async的基本使用


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   //获取并发global队列
    dispatch_sync(queue, ^{


        //在这里可以请求网络数据,因为不是主线程,所以这里的耗时不会阻塞到主线程


        dispatch_sync(dispatch_get_main_queue(), ^{


            //当耗时的操作(如网络请求)结束后,主线程进行的操作(如刷新UI)


        });
    });


二.dispatch_group_async的使用


现在如果有一个需求,有3个任务正在下载,如果需要实现当3个任务同时下载完成后,通知用户下载完成,可以使用dispatch_group_async和dispatch_get_global_queue


dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  //创建global队列
    dispatch_group_t group = dispatch_group_create();                                                                                          //创建group
    dispatch_group_async(group, globalQueue, ^{          
        //模拟3个任务下载完成
        dispatch_async(globalQueue, ^{
            NSLog(@"任务1下载完成");
        });
        dispatch_async(globalQueue, ^{
            NSLog(@"任务2下载完成");
        });
        dispatch_async(globalQueue, ^{
            NSLog(@"任务3下载完成");
        });
        
        //当3个任务下载完成时,发送通知到主线程
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"下载成功!!!!!");
        });
    });


发送通知还可以使用

dispatch_group_wait(group,DISPATCH_TIME_FOREVER)


输出结果为:

 任务3下载完成
 任务1下载完成
 任务2下载完成
下载成功!!!!!

输出的顺序与添加进队列的顺序无关,因为队列是global queue 也就是 Concurrent Dispatch Queue,“下载成功!!!!!"的输出一定是在最后的


3.dispatch_barrier_async的使用

barrier --->屏障

-------------任务0正在执行-------------任务0结束->执行dispatch_barrier_async----------------dispatch_barrier_async结束--------------------任务1开始--------

意思就是barrier要等待前面的任务结束后它才执行,它后面的任务要等待barrier执行完后才能执行,就是任务0和任务1中间的一块"挡板"

    dispatch_queue_t queue = dispatch_queue_create("com.Master", DISPATCH_QUEUE_CONCURRENT);     //创建concurrentQueue
    dispatch_async(queue, ^{
        NSLog(@"Task0");         //执行任务0
    });
    dispatch_async(queue, ^{
        NSLog(@"Task1");         //执行任务1
    });
    dispatch_barrier_async(queue, ^{
        //barrier
        NSLog(@"this is barrier");
    });
    dispatch_async(queue, ^{
        NSLog(@"Task2");         //执行任务2
    });
    dispatch_async(queue, ^{
        NSLog(@"Task3");         //执行任务3
    });


打印结果为:

Task0
Task1
this is barrier
Task3
Task2


--------------------------------------------如果把concurrentQueue换成serialQueue或者global会怎么样?

测试1:serialQueue


dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"Task0");         //执行任务0
    });
    dispatch_async(queue, ^{
        NSLog(@"Task1");         //执行任务1
    });
    dispatch_barrier_async(queue, ^{
        //barrier
        NSLog(@"this is barrier");
    });
    dispatch_async(queue, ^{
        NSLog(@"Task2");         //执行任务2
    });
    dispatch_async(queue, ^{
        NSLog(@"Task3");         //执行任务3
    });


打印结果:

Task0
Task1
this is barrier
Task2
Task3


这是必然的,因为serial本来就是串行队列,不是并发执行的,所以barrier在中间



测试2:global 默认优先级 DISPATCH_QUEUE_PRIORITY_DEFAULT

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(queue, ^{
        NSLog(@"Task0");         //执行任务0
    });
    dispatch_async(queue, ^{
        NSLog(@"Task1");         //执行任务1
    });
    dispatch_barrier_async(queue, ^{
        //barrier
        NSLog(@"this is barrier");
    });
    dispatch_async(queue, ^{
        NSLog(@"Task2");         //执行任务2
    });
    dispatch_async(queue, ^{
        NSLog(@"Task3");         //执行任务3
    });


打印结果:

第一次

Task0
this is barrier
Task2
Task1
Task3

第二次

Task1
Task0
this is barrier
Task2
Task3

第三次

Task2
Task1
Task0
Task3
this is barrier

第四次

Task1
Task2
Task0
this is barrier
Task3

.....经过N次打印,发现barrier完全无效了.个人猜想是否是默认优先级的问题?


试试DISPATCH_QUEUE_PRIORITY_LOW  DISPATCH_QUEUE_PRIORITY_BACKGROUND DISPATCH_QUEUE_PRIORITY_HIGH

发现结果一样,barrier失效

研究研究...


4.dispatch_apply 重复执行

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(5, queue, ^(size_t count) {  //5是重复次数
        NSLog(@"%zu",count);
    });
    NSLog(@"End");

打印:

1
 2
4
 0
 3
End

因为是concurrentQueue,所以count的执行顺序是不确定的,但是end肯定是在dispatch_apply之后所执行的,说明dispatch_apply是同步的,为了不影响阻塞主线程,应该把dispatch_apply放入dispatch_async里面


dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        dispatch_apply(5, queue, ^(size_t count) {  //5是重复次数
            NSLog(@"%zu",count);
        });
    });
    NSLog(@"End");


打印结果:

End
 0
 2
 1
 3
 4


perfect!这样就不会阻塞线程了


5.dispatch_after 延迟多少s后执行

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"5s后执行");
    });
    NSLog(@"nextStep");

打印结果:

a
5s后执行

不会阻塞线程

6.dispatch_suspend暂停 / dispatch_resume 恢复


    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  //创建一个global线程
    dispatch_async(queue, ^{
        for (int i = 0; i<10; i++) {         
        
  //定义一个for循环
            NSLog(@"%d",i);
            if (i == 4) {                                        //当i=4的时候
                dispatch_suspend(queue);         //线程暂停
                NSLog(@"暂停了");
                sleep(5);                                     //暂停5s
                dispatch_resume(queue);          //5s过后继续执行
            }
        }
    });


7.dispatch_once 只执行一次  (可以用来创建单例)


Dog.h


#import <Foundation/Foundation.h>
@interface Dog : NSObject
+(Dog *)sharedDog;
@end


Dog.m

#import "Dog.h"

@implementation Dog
+ (Dog *)sharedDog{
    
    static Dog * sharedClient = nil;           //设置为static静态变量,避免下次进来指向nil
    
    static dispatch_once_t onceToken;    //创建一个静态Token
    
    dispatch_once(&onceToken, ^{         //只执行一次
        
        sharedClient = [[Dog alloc] init];    //创建单例
        
    });
    
    return sharedClient;
    
}
@end


8.最后,GCD还有一个用处,可以让程序在后台运行更长的时间

在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。

但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据,后台播放音乐等工作。


// AppDelegate.h文件
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;

// AppDelegate.m文件
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self beingBackgroundUpdateTask];
    // 在这里加上你需要长久运行的代码
    [self endBackgroundUpdateTask];
}

- (void)beingBackgroundUpdateTask
{
    self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundUpdateTask];
    }];
}

- (void)endBackgroundUpdateTask
{
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
    self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值