ios之GCD学习笔记(1)

//1、 dispatch_once_t 用法

    static dispatch_once_t onceToken;
    //必须保证只有一个实力,才能确保只执行一次
    dispatch_once(&onceToken, ^{
        //单例代码
    });


    

    

    

    //2、dispatch_queue_t

    /*

     一共有三种

     2.1、主队列   dispatch_get_main_queue()

     由于主线程只有一个,所以Main自然是串行的。所添加的task会增加到主runloop

     主要进行一些更新页面的操作,由于是系统提供的所以调用dispatch_release()或者dispatch_retain()不会有任何作用,同时也不会有任何问题。*/

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    /*

     

     2.2、global队列dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

     第一个参数我优先级

     DISPATCH_QUEUE_PRIORITY_HIGH   高

     DISPATCH_QUEUE_PRIORITY_DEFAULT 默认

     DISPATCH_QUEUE_PRIORITY_LOW   低

     DISPATCH_QUEUE_PRIORITY_BACKGROUND 后台

     第二个参数为系统保留参数,写0即可

     

     通过方法可以生成一个系统默认的并发队列,它无法调用dispatch_resume()和dispatch_suspend(),与main一样调用dispatch_release()或者dispatch_retain()不会有任何作用,同时也不会有任何问题。

     需要注意的是,三个队列不代表三个线程,可能会有更多的线程。并发队列可以根据实际情况来自动产生合理的线程数,也可理解为dispatch队列实现了一个线程池的管理,对于程序逻辑是透明的。*/

    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH0);

    /*

     2.3、自定义队列

     dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

     第一个参数为队列的id,是一个CString,第二个参数是队列的属性。

     通常属性用以下两个宏

     DISPATCH_QUEUE_SERIAL   串行队列

     (实际上我们发现这个宏实际上是NULL)

     DISPATCH_QUEUE_CONCURRENT  并行队列

     

     

     通过该方法就可以生成一个自定义队列

     当存在多个串行队列的时候,多个队列是并行执行的,每个串行队列会生成一个线程。

     串行队列每个时刻只能执行一个任务

     并行队列多个任务同时执行

     

     最后注意:dispatch_queue_create的队列必须自己进行内存管理dispatch_release()或者dispatch_retain()

     

     */

   

 dispatch_queue_t typeDefQueue = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t typeDefConQueue = dispatch_queue_create("myConQueue", DISPATCH_QUEUE_CONCURRENT);
    
    __block BOOL aFin,bFin,cFin;
    static NSTimeInterval time = 0;
    time = [[NSDate new] timeIntervalSince1970];
    
    void(^Finish)(BOOL,BOOL,BOOL)=^(BOOL a,BOOL b,BOOL c){
        if (a&&b&&c) {
            NSTimeInterval oldTime = time;
            NSTimeInterval newTime = [[NSDate new] timeIntervalSince1970];
            NSLog(@"%d",(int)(newTime-oldTime));
        }
    };
    dispatch_async(typeDefQueue, ^{
        sleep(1);
        NSLog(@"1");
        aFin = YES;
        Finish(aFin,bFin,cFin);
    });
    dispatch_async(typeDefQueue, ^{
        sleep(1);
        NSLog(@"2");
        bFin = YES;
        Finish(aFin,bFin,cFin);
    });
    dispatch_async(typeDefQueue, ^{
        sleep(1);
        NSLog(@"3");
        cFin = YES;
        Finish(aFin,bFin,cFin);
    });
    
    /*
     【等待一秒】 1
     【等待一秒】      2
     【等待一秒】           3   3秒
     */
    
    
    dispatch_async(typeDefConQueue, ^{
        sleep(1);
        NSLog(@"a");
        aFin = YES;
        Finish(aFin,bFin,cFin);
    });
    dispatch_async(typeDefConQueue, ^{
        sleep(1);
        NSLog(@"b");
        bFin = YES;
        Finish(aFin,bFin,cFin);
    });
    dispatch_async(typeDefConQueue, ^{
        sleep(1);
        NSLog(@"c");
        cFin = YES;
        Finish(aFin,bFin,cFin);
    });
    
    /*
     【等待一秒】      a  1秒
     【等待一秒】b
     【等待一秒】   c
     */
    

    

    /*

     3、dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);与

     dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

     第一个参数是一个队列

     第二个参数是一个空参数空返回值的block

     

     dispatch_sync该方法会阻塞当前线程,知道当前追加的任务执行完毕

     dispatch_async该方法不会阻塞当前线程,立即返回

     

     实际编程经验告诉我们,尽可能避免使用dispatch_sync,嵌套使用时还容易引起程序死锁。

     切记不要使用以下写法,必然死锁

     dispatch_sync(dispatch_get_main_queue(), ^{

     });

     原因分析:这段代码会阻塞主线程,然而block有时在主线程执行,所以会造成死锁

     dispatch_sync(typeDefQueue, ^{

     dispatch_sync(typeDefQueue, ^{

     });

     });

     类似于这种情况。两个sync嵌套。

     

     问题:在并行队列里面用dispatch_async追加任务后,立刻调用dispatch_release是否可以?

     答:是完全没有问题的。因为queue会被block持有,所以只有等到block执行完毕,才会释放queue。

     

     举一反三:所有的gcd的create方法,都应该用对应的内存管理函数进行内存管理。

     

     3.1 void dispatch_async_f(dispatch_queue_t queue,void *context,dispatch_function_t work);

     与

     void dispatch_sync_f(dispatch_queue_t queue,void *context,dispatch_function_t work);

     

     第一个参数为队列

     第二个参数为上下文,作为work的参数

     第三个参数为返回值为空,参数为void*的函数指针(注意是函数指针)

     

     该方法主要用于调用C函数,跟dispatch_sync/dispatch_async逻辑上一样

     */


    dispatch_async_f(global, (void *)@"呵呵",workFunc);

    /*

     4、void

     dispatch_apply(size_t iterations, dispatch_queue_t queue,

     void (^block)(size_t));

     

     dispatch_apply, 作用是把指定次数指定的block添加到queue中, 第一个参数是迭代次数,第二个是所在的队列,第三个是当前索引,dispatch_apply可以利用多核的优势,所以输出的index顺序不是一定的.但是记住apply会阻塞当前线程,所以最好不要在主线程使用该方法。

     

     

     void  dispatch_apply_f(size_t iterations, dispatch_queue_t queue,

            void *context,void (*work)(void * datas, size_t idx));

     该方法与dispatch_async_f类似,不过第三个参数的函数指针,要多一个索引

     */

    dispatch_async(global, ^{
        dispatch_apply(10, global, ^(size_t idx) {
            NSLog(@"%zu",idx);
        });
    });


    /*

     5、const char *

     dispatch_queue_get_label(dispatch_queue_t queue);

     获得当前队列的标签

     

     6、void dispatch_set_target_queue( dispatch_object_t object, dispatch_queue_t queue );

    为给定的对象绑定一个目标队列

     该方法有两个作用

     I 设置队列的优先级

     如果你想让你的自定义队列的优先级等于系统队列。

     但是你无法设置系统队列的优先级,那么你就可以通过这个方法

     将两个队列的优先级相等。

     

     dispatch_queue_t serialQueue = dispatch_queue_create("myQueue",NULL);

     dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);

     dispatch_set_target_queue(serialQueue, globalQueue);

     

     II 设置队列之前的层级

     多个串行队列是并行的,用这个方法可以让多个子队列被父队列调度,可以实现让多个串行队列也是串行

     */

   

 dispatch_queue_t myQueue1 =  dispatch_queue_create("mySerial1", NULL);
    dispatch_queue_t myQueue2 = dispatch_queue_create("mySerial2", NULL);
    dispatch_queue_t targetSerial = dispatch_queue_create("target", NULL); //父队列
    dispatch_set_target_queue(myQueue1,targetSerial);
    dispatch_set_target_queue(myQueue2, targetSerial);
    
    dispatch_async(myQueue1, ^{
        sleep(1);
        NSLog(@"1_1");
    });
    
    dispatch_async(myQueue2, ^{
        NSLog(@"2_1");
    });
    
    dispatch_async(myQueue1, ^{
        NSLog(@"1_2");
    });
    
    dispatch_async(myQueue2, ^{
        sleep(1);
        NSLog(@"2_2");
    });

    /*

     7、 void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,

                dispatch_block_t block);

     该方法用于推迟执行block

     实际上并不是按照指定时间执行block,而是指定时间把block加入到queue

     对于要求非常精确地程序,并不适合用该方法

     

     第一个参数是推迟时间 dispatch_time_t类型也可以简单的直接写NSTimeInterval

     第二个参数是队列

     第三个参数是要执行的块

     

     dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);

     该方法创建一个dispatch_time_t

     第一个参数是表示现在的时间

     第二个参数表示间隔时间

     

     dispatch_time_t dispatch_walltime(const struct timespec *when, int64_t delta);

     该方法可以将 struct timespec类型的值 转成dispatch_time_t类型的值

     其是用于计算绝对时间,可以用于实现闹钟

     */

    

    dispatch_time_t(^GetDispatchTimeByData)(NSDate*) =^(NSDate *date)
    {
        NSTimeInterval interval;
        double second,subsecond;
        struct timespec time;
        dispatch_time_t milestone;
        interval = [date timeIntervalSince1970];
        subsecond = modf(interval, &second);
        time.tv_sec = second;
        time.tv_nsec = subsecond * NSEC_PER_SEC;
        milestone = dispatch_walltime(&time, 0);
        return milestone;
    };
    
    dispatch_time_t dTime = dispatch_time(DISPATCH_TIME_NOW, 1000ull*NSEC_PER_MSEC);
    dispatch_after(dTime, mainQueue, ^{
        NSLog(@"推迟了一秒");
    });
    dTime = GetDispatchTimeByData([NSDate dateWithTimeIntervalSinceNow:2]);
    dispatch_after(dTime, mainQueue, ^{
        NSLog(@"推迟了两秒");
    });


    


    

    /*

     void dispatch_after_f(dispatch_time_t when,dispatch_queue_t queue,

        void *context,dispatch_function_t work);

     该方法跟dispatch_sync_f方法类似

     

     

     8、dispatch_group_t  dispatch_group_create(void);

     创建一个group对象

     

     9、void dispatch_group_async(dispatch_group_t group,

            dispatch_queue_t queue,dispatch_block_t block);与

         void dispatch_group_notify(dispatch_group_t group,

            dispatch_queue_t queue,dispatch_block_t block);

     如果你想在多个异步操作全部完成之后,进行某个特定操作,比如刷新UI。

     那么你就不能轻易的像串行那样追加到后面了。

     group可以很好的解决这个问题

     可以通过dispatch_group_async将加入异步任务

     通过dispatch_group_notify添加所有任务完成的任务

     

     */

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, myQueue, ^{
        NSLog(@"任务1");
    });
    dispatch_group_async(group, myQueue, ^{
        NSLog(@"任务2");
    });
    dispatch_group_async(group, myQueue, ^{
        NSLog(@"任务3");
    });
    dispatch_group_notify(group, myQueue, ^{
        NSLog(@"全部完成");
    });
 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值