【问题标题】:What is the correct way to release a GCD dispatch queue property?释放 GCD 调度队列属性的正确方法是什么?
【发布时间】:2011-04-01 08:20:54
【问题描述】:

我正在使用通过其所有者的属性访问的 dispatch_queue,如下所示:

@property (nonatomic, assign) dispatch_queue_t queue;

注意assign 关键字。队列在对象的整个生命周期中使用,因此归对象所有。当拥有对象被释放时,我释放队列:

-(void)dealloc
{
    dispatch_release(self.queue);
    self.queue = nil;
}

如何正确释放它?使用retain/release 会起作用吗?

如果在调用释放时队列中有待处理/正在运行的东西会发生什么?

【问题讨论】:

    标签: objective-c memory-management grand-central-dispatch


    【解决方案1】:

    以下内容是从开发者文档中窃取的:

    调度队列和其他调度 对象是引用计数数据 类型。当你创建一个序列时 调度队列,它有一个初始 引用计数为 1。您可以使用 dispatch_retain 和 dispatch_release 递增和递减函数 根据需要引用计数。什么时候 队列的引用计数达到 零,系统异步 释放队列。

    当您的应用不再需要时 调度队列,它应该释放 它与 dispatch_release 功能。 任何提交给 queue 持有对该队列的引用, 所以队列不会被释放,直到 所有待处理的块都已完成。

    注意:您不需要保留或 释放任何全局调度 队列,包括并发 调度队列或主调度 队列。任何试图保留或 释放队列被忽略。

    因此,在任何使用 -retain 的地方都使用 dispatch_retain,在任何使用 -release 的地方都使用 dispatch_release。

    调度队列遵循与objective-c 对象相同的通用内存管理约定。在所有排队的块完成之前,它们不会被释放。

    如果您确实想要一种关闭调度队列的方法:无法通过任何类型的 API 取消所有排队的块,因此它们始终必须运行到完成。加快此过程的一种方法是在管理调度队列的类中设置一个 BOOL 变量:_isValid。当您想关闭队列时,您可以将_isValid 设置为NO。所有提交到队列的块在做任何工作之前都应该先检查_isValid。

    附注:使用 NSOperationQueue 可能更合适。请参阅 Chris Hanson 的blog post

    【讨论】:

    • 当然,如果你在类中有一个 _isValid,它是在 dealloc 中设置的,那么该对象将被销毁,这意味着 _isValid 不能再被安全地读取 - 有什么办法解决这个问题?
    • 实际上调用 dispatch_group_wait 似乎可以完全避免这个问题。
    • @CiscolPPhone “对象将被销毁”——实际上,访问块内的属性不会增加其保留计数,因此它会一直保持到块完成,即使在 dealloc 之后?我对此感到厌烦,所以我通常只引用块中的弱属性(在块之前我创建了一个__weak MyClass weakSelf = self,然后在块中只使用weakSelf.property。然后如果块在dealloc之后执行它只是命中一个无 weakSelf.property 并安全死亡。)
    • 关于无法取消入队块的问题。这来自 OSX 上的手册页:“如果在源挂起时更改事件处理程序块,或者从在作为源的目标队列的串行队列上运行的块更改,则下一个事件处理程序调用将使用新的堵塞。”另外:“要取消设置事件处理程序,请调用 dispatch_source_set_event_handler_f() 并将 NULL 作为函数传递。” (甚至取消注册一个块)。
    • @CiscoIPPhone Stephen 在 SO 上不活跃。你能回答这个问题吗:他说:“任何保留或释放队列的尝试都会被忽略。”然后说“任何你会使用 -release 的地方都使用 dispatch_release。” 如果 dispatch_release 被忽略,我为什么要使用它?!
    【解决方案2】:

    关于这个的一个有趣的事情是,如果提交到队列的块引用拥有队列的对象(例如“self”),则对象将不会命中dealloc,直到队列中的所有待处理块都完成为止。

    这里有一个项目可以证明这一点:

    https://github.com/joshrl/GDCQueueDeallocTest

    【讨论】:

      【解决方案3】:

      如果有东西会发生什么 在队列中挂起/运行时 调用释放?

      这是安全的。挂起/运行队列从系统中保留。调用 dispatch_release 只会影响队列的保留计数。请参阅 dispatch_async 的手册页等。

      【讨论】:

        【解决方案4】:

        像这样设置你的属性:

        @property (readwrite, strong, nonatomic) __attribute__((NSObject)) dispatch_queue_t queue;
        

        Assign 是隐含的,Strong 将保留告诉 ARC 将其视为 NSObject 的队列。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-05
          • 2011-08-31
          • 2021-08-13
          • 2011-08-29
          • 1970-01-01
          • 2011-09-13
          • 2011-12-13
          相关资源
          最近更新 更多