美文网首页
dispatch_object_t详解

dispatch_object_t详解

作者: 野码道人 | 来源:发表于2021-08-19 20:56 被阅读0次

    定义在object.h中,是dispatch系列数据结构的基础结构,类似于NSObject基类,如dispatch_queue_t、dispatch_group_t、dispatch_source_t等都可以直接调用dispatch_object_t相关的函数,GCD使用宏定义隐藏了其内部实现,其实他们都是遵循同一个协议的NSObject类型的对象,如下图

    object.h内部定义了一系列内存语义和操作函数,如下

    dispatch_object_t内存语义

    void dispatch_retain(dispatch_object_t object); // MRC下retain内存语义
    void dispatch_release(dispatch_object_t object); // MRC下release内存语义
    

    MRC下内存管理语句,ARC下禁用

    dispatch_object_t绑定上下文

    void dispatch_set_context(dispatch_object_t object, void *context); // 给dispatch对象绑定上下文
    void *dispatch_get_context(dispatch_object_t object); // 返回dispatch对象绑定的上下文
    void dispatch_set_finalizer_f(dispatch_object_t object, dispatch_function_t finalizer); // 绑定函数指针,当dispatch任务执行完毕会通过该函数回调并且带回绑定的上下文
    

    注意:

    只有由dispatch_queue_create创建出来的队列设置上下文才有效,主队列dispatch_get_main_queue和全局队列dispatch_get_global_queue(0, 0)苹果禁止修改上下文,因为苹果有自己的实现,因此我们常说这两个是特殊的队列

    演示:

    void finalizer(void *context) {
        id object = (__bridge_transfer id)context;
        NSLog(@"执行finalizer:%@", object);
    }
    
    dispatch_queue_t dispatchObject = dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    void *context = (__bridge_retained void *)self;
    dispatch_set_context(dispatchObject, context);
    dispatch_set_finalizer_f(dispatchObject, finalizer);
    NSInteger count = 10;
    while (count--) {
        dispatch_async(dispatchObject, ^{
            usleep(1000 * 1000); // 线程休眠一秒
            NSLog(@"dispatchObject %ld:执行完毕", (long)count);
        });
    }
    

    输出:

    2021-08-19 15:30:14.484310+0800 GCDDemo[3254:1673360] dispatchObject 9:执行完毕
    2021-08-19 15:30:14.484553+0800 GCDDemo[3254:1673359] dispatchObject 8:执行完毕
    2021-08-19 15:30:14.485017+0800 GCDDemo[3254:1673358] dispatchObject 7:执行完毕
    2021-08-19 15:30:14.487532+0800 GCDDemo[3254:1673368] dispatchObject 1:执行完毕
    2021-08-19 15:30:14.487604+0800 GCDDemo[3254:1673369] dispatchObject 0:执行完毕
    2021-08-19 15:30:14.489625+0800 GCDDemo[3254:1673363] dispatchObject 6:执行完毕
    2021-08-19 15:30:14.489760+0800 GCDDemo[3254:1673357] dispatchObject 5:执行完毕
    2021-08-19 15:30:14.490028+0800 GCDDemo[3254:1673364] dispatchObject 4:执行完毕
    2021-08-19 15:30:14.490185+0800 GCDDemo[3254:1673365] dispatchObject 3:执行完毕
    2021-08-19 15:30:14.490442+0800 GCDDemo[3254:1673367] dispatchObject 2:执行完毕
    2021-08-19 15:30:14.492204+0800 GCDDemo[3254:1673367] 执行finalizer:<ViewController: 0x153f09550>
    

    使用场景:

    如上待到所有并发任务执行完成,就会执行finalizer函数,当然串行队列也是一样,只是会按照顺序执行,当一组任务执行完毕的时候需要执行一个统一的操作,这个时候就可以用绑定上下文来实现

    当然苹果给我们提供了更便捷的dispatch_group_t系列api,这个后面文章再讲

    dispatch_activate

    定义如下,用于激活非激活状态dispatch_object_t

    void
    dispatch_activate(dispatch_object_t object); 
    

    注意:

    主队列dispatch_get_main_queue和全局队列dispatch_get_global_queue(0, 0)是激活态的,我们通过dispatch_queue_create创建的队列可以用第二个参数指定激活状态

    • DISPATCH_QUEUE_SERIAL 串行队列
    • DISPATCH_QUEUE_SERIAL_INACTIVE 非激活态串行队列
    • DISPATCH_QUEUE_CONCURRENT 并发队列
    • DISPATCH_QUEUE_CONCURRENT_INACTIVE 非激活态并发队列

    演示:

    self.concurrentQueue = dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT_INACTIVE);
    NSInteger count = 10;
    while (count--) {
        dispatch_async(self.concurrentQueue, ^{
            usleep(1000 * 1000); // 线程休眠一秒
            NSLog(@"dispatchObject %ld:执行完毕", (long)count);
        });
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        dispatch_activate(self.concurrentQueue);
    });
    

    输出

    2021-08-19 17:23:32.521423+0800 GCDDemo[3317:1706577] dispatchObject 9:执行完毕
    2021-08-19 17:23:32.521596+0800 GCDDemo[3317:1706571] dispatchObject 8:执行完毕
    2021-08-19 17:23:32.521444+0800 GCDDemo[3317:1706597] dispatchObject 0:执行完毕
    2021-08-19 17:23:32.522131+0800 GCDDemo[3317:1706573] dispatchObject 7:执行完毕
    2021-08-19 17:23:32.522333+0800 GCDDemo[3317:1706578] dispatchObject 6:执行完毕
    2021-08-19 17:23:32.522519+0800 GCDDemo[3317:1706592] dispatchObject 5:执行完毕
    2021-08-19 17:23:32.522710+0800 GCDDemo[3317:1706593] dispatchObject 4:执行完毕
    2021-08-19 17:23:32.522895+0800 GCDDemo[3317:1706594] dispatchObject 3:执行完毕
    2021-08-19 17:23:32.522985+0800 GCDDemo[3317:1706595] dispatchObject 2:执行完毕
    2021-08-19 17:23:32.523146+0800 GCDDemo[3317:1706596] dispatchObject 1:执行完毕
    

    使用场景:

    可以用于构建备忘录模式,进行操作存档,当然与传统备忘录模式还有些区别,备忘录模式可以单步回档

    dispatch_suspend与dispatch_resume

    定义如下,用于执行和挂起dispatch_object_t

    void
     dispatch_resume(dispatch_object_t object); // 执行
    void 
    dispatch_suspend(dispatch_object_t object); // 挂起
    

    注意:

    处于非激活态的队列,直接调用dispatch_resume运行时会crash

    演示:

    dispatch_queue_t concurrentqueue = dispatch_queue_create("com.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_suspend(concurrentqueue);
    dispatch_async(concurrentqueue, ^{
        NSLog(@"任务执行完毕");
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        dispatch_resume(concurrentqueue);
    });
    NSLog(@"代码执行到这里");
    

    输出:

    2021-08-19 20:32:24.400530+0800 GCDDemo[3364:1742868] 代码执行到这里
    2021-08-19 20:32:29.890087+0800 GCDDemo[3364:1742884] 任务执行完毕
    

    使用场景:

    可以用于支持一组任务的暂停继续操作,例如多线程下载大文件,当然正在执行的任务是无法取消的,理论上也不允许,会有很多内存方面的问题

    dispatch_wait、dispatch_notify、dispatch_cancel、dispatch_testcancel

    定义如下,会根据object的类型映射成子类型的函数

    intptr_t
    dispatch_wait(void *object, dispatch_time_t timeout);
    void
    dispatch_notify(void *object, dispatch_object_t queue, 
            dispatch_block_t notification_block);
    void
    dispatch_cancel(void *object);
    intptr_t
    dispatch_testcancel(void *object);
    

    映射关系:

    dispatch_wait前两个会阻塞当前线程,第三个执行后小于0阻塞当前线程
    dispatch_block_t:dispatch_block_wait
    dispatch_group_t:dispatch_group_wait
    dispatch_semaphore_t:dispatch_semaphore_wait

    dispatch_notify一组任务执行完毕后调用
    dispatch_block_t:dispatch_block_notify
    dispatch_group_t:dispatch_group_notify

    dispatch_cancel用于取消没有执行的任务
    dispatch_block_t:dispatch_block_cancel
    dispatch_source_t:dispatch_source_cancel

    dispatch_testcancel检测任务是否被取消
    dispatch_block_t:dispatch_block_testcancel
    dispatch_source_t:dispatch_source_testcancel

    相关文章

      网友评论

          本文标题:dispatch_object_t详解

          本文链接:https://www.haomeiwen.com/subject/dgzobltx.html