4
votes

I noticed Apple's documentation saying we need to avoid strong reference cycles when capturing self.

The block in the example is a property of self.

But what if I put a block as a local variable in a dispatch_async statement?

In this case, it will not create a retain cycle even if I directly call a method of self, right?

Is the following code generating weakSelf required in this article?

// your code
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doThis];
        [strongSelf doThat];
        [Manager.sharedInstance updateSuccessCount];
    }
});

// more code
1
Update your question with relevant code.rmaddy
You’re right, this will not result in a cycle since the block itself is released when the callback is called. But if the callback were stored in a variable, you should consider when (and if) it is released. In Apple’s example, the block is only released when self.block is re-assigned or self is released. However, self will never be released since there’s always the reference from the block still around.Raphael Schweikert
@rmaddy Hi I've updated the code here.Yao Fan
@RaphaelSchweikert Thanks, I agree with you. I just updated the question with some sample code.Yao Fan
Just a side note, the code above doesn't guarantee that strongSelf will be valid. If weakSelf becomes nil right before the assignment statement then strongSelf will be nil. All that strongSelf guarantees here is that it will be either a valid object or nil for the remainder of the block. If you want to guarantee the object is non-nil, put the strongSelf declaration just before the if statement and check to see if strongSelf is nil instead.Lucas Derraugh

1 Answers

6
votes

In the example given, using dispatch_async, there would be no retain cycle, so it would be safe to capture self strongly here. The only difference would be that if self were released by everything else between when this dispatch_async was called and when the block actually ran, it would slightly delay the actual deallocation of self for that brief time, and could affect which thread the deallocation actually occurs on as well. But in general there's no harm in doing it either way when using dispatch_async.

One case where you may want to do it the way your example is written above is if the code run in the block is somewhat expensive and would only want to be done if absolutely necessary, and that it's unnecessary if self had already been released by everything else.

Another case may be if self uses a large amount of memory and gets deallocated normally right before something else starts consuming a lot of memory. In that case you may not want those two instances to be allocated at the same time.