5

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.

Ben Flynn
  • 18,524
  • 20
  • 97
  • 142

2 Answers2

3

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.

WDUK
  • 18,870
  • 3
  • 64
  • 72
  • 1
    This is why I prefer `self->ivar.property`, because I can _see_ it retains `self`. Not just `ivar.property`, which in fact gets expanded by `self->`. – Tricertops Feb 07 '13 at 20:39
  • It is not a good idea to use self->ivar if self become nil it would cause a crash. It is better to define it as property when you use it in a block, and use __weak self to prevent retain cycle. – Zeev Vax Apr 26 '14 at 04:08
0

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.

MadhavanRP
  • 2,832
  • 1
  • 20
  • 26
  • "My initial thought was that because it is an instance variable, self also gets retained until the block..." No, `queue` is not used inside any of the blocks that I can see – newacct Feb 07 '13 at 21:19