Suppose I have a class (non-ARC environment):
@interface SomeObject : NSObject {
UILabel *someLabel;
dispatch_queue_t queue;
}
- (void)doAsyncStuff;
- (void)doAnimation;
@end
@implementation SomeObject
- (id)init {
self = [super init];
if (self) {
someLabel = [[UILabel alloc] init];
someLabel.text = @"Just inited";
queue = dispatch_queue_create("com.me.myqueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)doAsyncStuff {
dispatch_async(queue, ^{
...
// Do some stuff on the current thread, might take a while
...
dispatch_async(dispatch_get_main_queue(), ^{
someLabel.text = [text stringByAppendingString:@" in block"];
[self doAnimation];
}
}
}
- (void)doAnimation {
...
// Does some animation in the UI
...
}
- (void)dealloc {
if (queue) {
dispatch_release(queue);
}
[someLabel release];
[super dealloc];
}
If my block gets kicked off and then everything else holding a reference to the instance of this object releases it, am I guaranteed that dealloc won't be called because the nested block refers to an instance variable (and to self) -- that dealloc will happen after the nested block exits? My understanding is that my block has a strong reference to self, so this should be kosher.
This is fine, for the reasons you've stated.
The important thing to note is that you would create a retain cycle, if the class (represented by
self
) retained the block in any way. Because you're defining it in-line, and passing it todispatch_async
, you should be ok.You are absolutely right. The block retains self in two cases:
Your nested block is good to go on both counts. Therefore, the dealloc will happen after the block has finished executing.
Another interesting thing to note is that your
queue
is also an instance variable. My initial thought was that because it is an instance variable,self
also gets retained until the block has finished executing. However, what actually happens when I tested it out is onlyqueue
gets retained andself
gets deallocated. I am not able to find documentation for this though.