ios之GCD学习笔记(1)

来源:互联网 发布:郎咸平小三 知乎 编辑:程序博客网 时间:2024/04/28 15:10

//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
原创粉丝点击