Ben Flynn
Ben Flynn

Reputation: 18932

Reference to instance variables inside a block

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.

Upvotes: 5

Views: 3091

Answers (2)

MadhavanRP
MadhavanRP

Reputation: 2830

You are absolutely right. The block retains self in two cases:

  1. You use self inside the block.
  2. You access an instance variable directly inside the block.

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 only queue gets retained and self gets deallocated. I am not able to find documentation for this though.

Upvotes: 0

WDUK
WDUK

Reputation: 19030

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 to dispatch_async, you should be ok.

Upvotes: 3

Related Questions