16

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];
    }
}
Rose Perrone
  • 61,572
  • 58
  • 208
  • 243
  • 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 Jul 24 '13 at 03:16
  • 2
    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 Jul 24 '13 at 03:20
  • @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 Jul 24 '13 at 04:00
  • 1
    @borrrden: the `__weak` on the right hand of the `*` is *the correct* way to write it. https://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW7 Putting it anywhere else is wrong but tolerated. – newacct Jul 24 '13 at 08:01
  • @newacct Oh dear, shame on me >_ – borrrden Jul 24 '13 at 08:34

1 Answers1

28

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.
    }
}
Darren
  • 25,520
  • 5
  • 61
  • 71
timothy lau
  • 386
  • 2
  • 2
  • 3
    It's not required that you check `strongSelf` in this particular example. You're allowed to send messages to `nil`; nothing happens. – rob mayoff Jul 24 '13 at 04:02
  • 7
    But what's the difference (besides silencing the warning)? – newacct Jul 24 '13 at 08:11
  • 1
    The `strongSelf` is not weak by type, but is actually 'pointing' to a weak pointer. For the compiler, it 'looks like' a strong pointer (although, ref count does not change). Of course, once the `weakSelf` is released, so do the `strongSelf`. Simply put, the `strongSelf` is a strong pointer, that does not raise the ref count. – bauerMusic Feb 28 '19 at 14:16
  • @bauerMusic are you sure? It if didn't bump the retain count, how would it maintain a strong reference? Thanks! – Dan Rosenstark Aug 30 '20 at 03:13
  • @DanRosenstark I wrote that the `strongSelf` does not raise the ref count. It's wrong. What I think I meant, it that when the block is copied, the retain count does not change, only when the block is called. You are correct, when the code in the block is running, the `strongSelf` will bump the ref count. – bauerMusic Aug 31 '20 at 05:23
  • Thanks for that, agreed. What I'm really interested in is whether `[weakSelf doSomething]` bumps the retain count (retaining weakSelf for the duration of the method call), or whether weakSelf can get deallocated while doSomething is running. – Dan Rosenstark Aug 31 '20 at 12:05