In a class, I've declared a thread like:
@property (nonatomic, strong) dispatch_queue_t databaseQueue;
and then I perform an operation this thread like
dispatch_async(self.databaseQueue, ^{
[self.dao deleteRetries];
});
Can this potentially create a retain cycle?
AND
the current class holds a strong reference to viewControllerToDismiss
and there is a code which looks like:
[viewControllerToDismiss dismissViewControllerAnimated:shouldAnimateDismiss completion:^{
[self performSomeAction];
}
is this a retain cycle?
It is merely a strong reference to self
that is eliminated automatically when the block finishes running and GCD releases the block. Note, this is a strong reference between the queue object itself, the block, and self
, but not to databaseQueue
. E.g. even if databaseQueue
was some local reference that had fallen out of scope after you dispatched but before it ran, you'd still have a strong reference between the queue object, the block, and self
.
If you don't want that strong reference at all, use weakSelf
pattern:
typeof(self) __weak weakSelf = self;
dispatch_async(self.databaseQueue, ^{
[weakSelf.dao deleteRetries];
});
You asked:
Please could you elaborate more on "Note, this is a strong reference between the queue object itself, the block, and self, but not to databaseQueue"?
Consider:
- (void)runManyTasks {
dispatch_queue_t queue = dispatch_queue_create("com.domain.app.foo", 0);
for (NSInteger i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self doSomething];
});
}
}
- (void)doSomething {
[NSThread sleepForTimeInterval:1];
}
Even though I have no references in my code to that local variable, queue
, after runManyTasks
finishes, if I call runManyTasks
, GCD will keep its own strong reference to the actual underlying queue object until all tasks finish, and the queue will keep copies of those blocks until they finish running, and those blocks will maintain a strong reference to self
until GCD finishes with all of them (roughly 10 seconds, in this example).
You go on to edit your question and ask:
the current class holds a strong reference to
viewControllerToDismiss
and there is a code which looks like:[viewControllerToDismiss dismissViewControllerAnimated:shouldAnimateDismiss completion:^{ [self performSomeAction]; }
is this a retain cycle?
For all practical considerations, no. That block is released as soon as the dismissal animation is done, so you generally wouldn't complicate your code with weakSelf
pattern here. In fact, that view controller isn't dismissed until the animation finishes, anyway, so there's absolutely nothing gained from weakSelf
pattern (other than making code more convoluted).
First, you have not declared a thread. It’s a queue, that’s something different. (Fortunately, as working directly with threads is a pain.)
You are dispatching a block into the queue. The block retains self
and the queue retains the block, which means you do have a retain cycle, since the queue, being a strong
property, is retained by self
:
self -> queue -> block -> self -> queue -> …
BUT the block should be short-lived, judging by the API. When the block is finished, it will get released from the queue, breaking the retain cycle. So I would not worry about a case like this.
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