Question

I recently learned this trick for when I have to reference self within a block.

__weak MyObject *safeSelf = self;  
[self doWithCompletionBlock:^{

    HMFInventoryBatchItemsController *strongSelf = safeSelf;
    if (strongSelf) {
        [strongSelf doSomethingElse];
    }
}];

But I've been wondering, what if I have a block within a block? Do I need to do the same thing again?

__weak MyObject *safeSelf = self;  
    [self doWithCompletionBlock:^{

        HMFInventoryBatchItemsController *strongSelf = safeSelf;
        if (strongSelf) {

            __weak MyObject *saferSelf = strongSelf;  
            [strongSelf doAnotherThingWithCompletionBlock:^{

                HMFInventoryBatchItemsController *strongerSelf = saferSelf;
                if (strongerSelf) {
                    [strongerSelf doSomethingElse];
                }
            }];
        }
   }];

Or is this fine

__weak MyObject *safeSelf = self;  
    [self doWithCompletionBlock:^{

        HMFInventoryBatchItemsController *strongSelf = safeSelf;
        if (strongSelf) {

            [strongSelf doAnotherThingWithCompletionBlock:^{

                    [strongSelf doSomethingElse];

            }];
        }
   }];
Was it helpful?

Solution

The good answer is, it depends. It's in general unsafe to do:

__weak MyObject *safeSelf = self;

[self doWithCompletionBlock:^{
      [safeSelf doAnotherThingWithCompletionBlock:^{
              [safeSelf doSomethingElse];
       }];
}];

The reason for that, is that when you call -doAnotherThingWithCompletionBlock if that method thinks it holds a reference on self, which a selector usually assumes, and it dereferences self to access ivars, then you will crash, because you actually don't hold a reference.

So whether you need to take a new weak reference or not depends on the lifetime semantics you need/want.

EDIT:

By the way, clang even has a warning about that issue that you can enable in Xcode with the CLANG_WARN_OBJC_RECEIVER_WEAK setting (CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK is also useful while we're at it)

OTHER TIPS

__block MyObject *safeSelf = self;

    [self doWithCompletionBlock:^{
          [safeSelf doAnotherThingWithCompletionBlock:^{
                  [safeSelf doSomethingElse];
           }];
   }];

Hope it will do what it should normally does. Tell the compiler not to retain the __weak MyObject* no matter in which block scope it is. The fact is i didn't tested. Meanwhile I'll be surprised if it will actually retain MyObject *

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top