21

I have reqest with block. But the compiler issues a warning

"Capturing 'self' strongly in this block is likely to lead to a retain cycle"

__weak typeof(self) weakSelf = self;
[generalInstaImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:data[@"images"][@"low_resolution"][@"url"]]] placeholderImage:[UIImage imageNamed:@"Default"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
    NSLog(@"success");
    [generalInstaImage setImage: image];
    [weakSelf saveImage:generalInstaImage.image withName:data[@"id"]];

    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
        NSLog(@"fail");
}];

I try example write like weakSelf.generalInstaImage, but then the compiler generates an error and do not compile.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
Alexander
  • 627
  • 2
  • 11
  • 23

2 Answers2

63

Consider this warning:

Capturing self strongly in this block is likely to lead to a retain cycle

When you receive the above warning, you should review your block for:

  • any explicit references to self; or
  • any implicit references to self caused by referencing any instance variables.

Let's imagine that we have some simple class property that was a block (this will experience the same "retain cycle" warnings as your question, but will keep my examples a little simpler):

@property (nonatomic, copy) void (^block)(void);

And let's assume we had some other class property we wanted to use inside our block:

@property (nonatomic, strong) NSString *someString;

If you reference self within the block (in my example below, in process of accessing this property), you will obviously receive that warning about the retain cycle risk:

self.block = ^{
    NSLog(@"%@", self.someString);
};

That is remedied via the pattern you suggested, namely:

__weak typeof(self) weakSelf = self;

self.block = ^{
    NSLog(@"%@", weakSelf.someString);
};

Less obvious, you will also receive the "retain cycle" warning if you reference an instance variable of the class inside the block, for example:

self.block = ^{
    NSLog(@"%@", _someString);
};

This is because the _someString instance variable carries an implicit reference to self, and is actually equivalent to:

self.block = ^{
    NSLog(@"%@", self->_someString);
};

You might be inclined to try to adopt weak self pattern here, too, but you can't. If you attempt the weakSelf->_someString syntax pattern, the compiler will warn you about this:

Dereferencing a __weak pointer is not allowed due to possible null value caused by race condition, assign it to strong variable first

You therefore resolve this by using the weakSelf pattern, but also create a local strong variable within the block and use that to dereference the instance variable:

__weak typeof(self) weakSelf = self;

self.block = ^{
    __strong typeof(self) strongSelf = weakSelf;

    if (strongSelf) {
        NSLog(@"%@", strongSelf->_someString);

        // or better, just use the property
        //
        // NSLog(@"%@", strongSelf.someString);
    }
};

As an aside, this creation of a local strong reference, strongSelf, inside the block has other advantages, too, namely that if the completion block is running asynchronously on a different thread, you don't have to worry about self being deallocated while the block is executing, resulting in unintended consequences.

This weakSelf/strongSelf pattern is very useful when dealing with block properties and you want to prevent retain cycles (aka strong reference cycles), but at the same time ensuring that self cannot be deallocated in the middle of the execution of the completion block.

FYI, Apple discusses this pattern in the "non-trivial cycles" discussion further down in the Use Lifetime Qualifiers to Avoid Strong Reference Cycles section of the Transitioning to ARC Release Notes.


You report that you received some "error" when you referenced weakSelf.generalInstaImage in your example. This is the correct way to resolve this "retain cycle" warning, so if you received some warning, you should share that with us, as well as show us how you declared the property.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 3
    Very complete answer! +1 – Lorenzo B Jun 09 '13 at 15:41
  • "will generate an exception" No, it will not generate an exception. It will lead to undefined behavior (likely a segmentation fault). – newacct Jun 10 '13 at 21:45
  • @newacct My main point was to dispel the notion of trying to dereference ivars with weak pointers, but I appreciate your clarification. – Rob Jun 10 '13 at 22:08
  • Good explanation about memory management and blocks, however in the question isn't clear that the block is a property of `generalInstaImage`. Sometimes XCode isn't smart enough to detect these cases, and this is one of them, because `setImageWithURLRequest:requestWithURL:placeholderImage:success:` is a method from `SDWebImage` and it doesn't seem to declare any block property. – Pablo A. Aug 12 '16 at 11:00
  • Pablo, yep, the compiler doesn't know whether the other class correctly avoids the strong reference cycle. It only knows that passing `self` could possibly result in such a cycle. (Perhaps their use of "likely" goes too far.) That having been said, we often program defensively, assuming that any asynchronous method _might_ keep a reference to the block. Ideally, we want our classes as loosely coupled as possible, we shouldn't make too many assumptions about how the other class behaves. IMHO, you should use `weakSelf` pattern, regardless, if you can. – Rob Nov 14 '17 at 19:05
2

Use __unsafe_unretained typeof(self) weakSelf = self

SandeepM
  • 2,601
  • 1
  • 22
  • 32
  • 3
    This may eliminate the compiler warning, but can have disastrous results if `self` was deallocated by the time the block is called, as you'll have a dangling pointer to a deallocated object. This is, at the risk of stating the obvious, very _unsafe._ – Rob Dec 18 '13 at 19:04