15
votes

Apple docs say I can avoid a strong reference cycle by capturing a weak reference to self, like this:

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // capture the weak reference
                                  // to avoid the reference cycle
    }
}

Yet when I write this code, the compiler tells me:

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

Yet doesn't the following code create a strong reference cycle, and possibly leak memory?

- (void)configureBlock {
    XYZBlockKeeper *strongSelf = self;
    self.block = ^{
        [strongSelf doSomething];
    }
}
1
Try __weak XYZBlockKeeper *weakSelf instead. I am uncomfortable seeing the __weak on the right-hand side of the * (this might not make a difference, but try it out. If it does then I have a theory why). - borrrden
Just as a sidenote, I can't get this message to come out either way. It is saying that you are doing something like weakSelf->memberVariable = 123; - borrrden
@borrden You get this warning if you set the -Wreceiver-is-weak flag (available as the “Sending messages to __weak pointers” build setting). Also, it's more sensible to put __weak after the star, because __weak applies to weakSelf (in that weakSelf will be set to zero, while *weakSelf will not be set to zero). Consider that typedef XYZBlockKeeper *XYZBlockKeeperRef; XYZBlockKeeperRef __weak weakSelf; declares a weak reference, but typedef __weak XYZBlockKeeper WeakXYZBlockKeeper; WeakXYZBlockKeeper *weakSelf; does not (and gets a warning that __weak doesn't apply). - rob mayoff
@borrrden: the __weak on the right hand of the * is the correct way to write it. developer.apple.com/library/mac/#releasenotes/ObjectiveC/… Putting it anywhere else is wrong but tolerated. - newacct
@newacct Oh dear, shame on me >_< - borrrden

1 Answers

27
votes

You should use like this one: eg:

__weak XYZBlockKeeper *weakSelf = self;

self.block = ^{

    XYZBlockKeeper *strongSelf = weakSelf;

    if (strongSelf) {
        [strongSelf doSomething];
    } else {
        // Bummer.  <self> dealloc before we could run this code.
    }
}