Reference to instance variables inside a block

2019-06-21 19:13发布

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.

2条回答
劫难
2楼-- · 2019-06-21 19:45

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.

查看更多
beautiful°
3楼-- · 2019-06-21 20:06

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.

查看更多
登录 后发表回答