I have an object, that on initialization creates a serial GCD queue using dispatch_queue_create
, and on deallocation calls dispatch_free
. During the lifetime of the object, dispatch blocks are added to the queue, however the queue is also stopped and started using dispatch_suspend
and dispatch_resume
.
My issue is that at one point the object may be released, and when deallocated I would, for the sake of tidiness, like to completely drop the dispatch queue and all dispatch_block_t
objects within it, regardless of wether or not the queue is suspended.
As I understand it, the queue will not deallocate until no longer 'needed' in the sense that it is no longer retained by the dispatch blocks within it. This leads me to believe that to deallocate the queue, I have to empty it by allowing blocks within it to execute to termination first.
What is the simplest and most robust way to go about this?
Generally this isn't something you should worry too much about. From Memory Management for Dispatch Queues in the Concurrency Programming Guide :
You can use the dispatch_retain and dispatch_release functions to increment and decrement that reference count as needed. When the reference count of a queue reaches zero, the system asynchronously deallocates the queue.
So when you call dispatch_release(myQueue)
, you're lowering the retain count, but any tasks still on the queue will be retaining the queue. It's not until these have finished that the retain count of the queue will be 0. So this part of your question:
This leads me to believe that to deallocate the queue, I have to empty it by allowing blocks within it to execute to termination first.
Is accurate. If you have tasks you may not want to run that are on the queue, keep reading.
If you're suspending and resuming the queue from your code, this doesn't cause a problem - because you MUST balance all suspend and resume calls. If you leave your queue in a suspended state, you're going to have a bad time.
That said, you also have the option to set a cleanup function for the queue, using dispatch_set_finalizer_f
. This shouldn't be necessary, but it's there if you need it.
Now, based on what you're describing here, I'd suggest using NSOperation and NSOperationQueue instead. It's a higher level layer on top of GCD that allows you to cancel tasks and do some other useful things that are much harder to do using GCD directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With