2

What if I have a class Foo declared like:

@interface Foo : NSObject
@property (copy, nonatomic) void (^aBlock)(void);
- (void)bar;
@end

@implementation Foo
- (void)bar {}
@end

and I store in Foo instance a block that captures this instance itself:

Foo *foo = [Foo new];

__weak Foo *weakFoo = foo;
foo.aBlock = ^{
    __strong Foo *strongFoo = weakFoo; <--- does this __strong Foo * really makes sense?

    [strongFoo bar];
}

... then somewhere later use foo.aBlock()

or I just do:

Foo *foo = [Foo new];

__weak Foo *weakFoo = foo;
foo.aBlock = ^{
    [weakFoo bar];
}

... then somewhere later use foo.aBlock()

Does adding of __strong *strongFoo = weakFoo makes any sense or is it enough to use just [weakFoo bar] inside a block?

Stanislav Pankevich
  • 11,044
  • 8
  • 69
  • 129
  • 1
    [This answer](http://stackoverflow.com/a/21114626/795339), though in response to a different question, states that the `__strong` variable is not always required. – Mike Mertsock Apr 10 '14 at 18:57

3 Answers3

5

In your example it's not strictly necessary to make a strong reference inside the block again: weakFoo will either be nil and the method is not called, or it's a valid reference and will stay valid for the duration of this call.

But consider the following snippet:

Foo *foo = [Foo new];

__weak Foo *weakFoo = foo;
foo.aBlock = ^{
    [weakFoo bar];
    [weakFoo baz];
}

... then somewhere later use foo.aBlock()

Now you introduced a race condition, where weakFoo could be valid for the first call, but nil for the second call. This is almost never what you want. In this case use __strong Foo *foo = weakFoo; to make sure you have the same value for both calls.

Edit:

Here is an example how you can trigger such a race condition:

@interface BlockHolder : NSObject
@property (nonatomic, copy) void(^block)(void);
@end

@implementation BlockHolder
@end


int main(int argc, const char * argv[])
{
    @autoreleasepool {
        BlockHolder *holder = [[BlockHolder alloc] init];

        __weak BlockHolder *weakHolder = holder;
        holder.block = ^{
            for (int i = 0; i < 10; i++) {
                NSLog(@"weakHolder is %@", weakHolder);
                sleep(1);
            }
        };

        dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);

        dispatch_async(queue, holder.block);

        sleep(2); // give the queue some time to start executing the block
        holder = nil;

        dispatch_sync(queue, ^{}); // wait for the queue to finish
    }
    return 0;
}
Alfonso
  • 8,386
  • 1
  • 43
  • 63
  • Can you explain why it wouldn't be valid in the second call? `[weakFoo baz];` – Logan Apr 10 '14 at 20:12
  • 1
    Because `__weak` references are only valid as long as there are also `__strong` references to the same object. If all `__strong` references are gone the `__weak` references are set to `nil`. If this happens while the block is executing, this can happen between calls. – Alfonso Apr 10 '14 at 20:27
2

You should use:

__weak NSObject * weakFoo = foo;  // Assign foo to weakFoo to avoid retain cycles
foo.block =
^{
    NSObject * strongFoo = weakFoo; // By default it is strong, no need for __strong prefix. Hold the weakFoo to make sure it is not nil out while block is executing.
    if (strongFoo != nil) // Nil check if you want to execute code in block if non-nil.
    {
       [strongFoo useIt];
    }
}
gagarwal
  • 4,224
  • 2
  • 20
  • 27
  • calling a message on `nil` does nothing anyway – newacct Apr 11 '14 at 05:23
  • @newacct You are right. But block can have more code and you may want to perform operations on other objects too. If strongFoo is nil then we do not want to execute any code in block (depend upon the app logic), and this will guard for this case. – gagarwal Apr 11 '14 at 15:49
1

There is a reason. The thing is, a __weak reference won't keep the object alive during the block. So, for example, if you have an asynchronous block, weakSelf could disappear halfway through the block's execution (because the weak reference doesn't keep the object alive). So we use a strongSelf inside the block to ensure that the object lives long enough to make it all the way through the block.

Chuck
  • 234,037
  • 30
  • 302
  • 389