解决保留周期:当我们已经有__weak*weakSelf时,是否真的有理由添加__strong*strongSelf?

Sta*_*ich 2 objective-c objective-c-blocks automatic-ref-counting

如果我有一个类Foo声明如下:

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

@implementation Foo
- (void)bar {}
@end
Run Code Online (Sandbox Code Playgroud)

我在Foo实例中存储了一个捕获此实例的块:

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()
Run Code Online (Sandbox Code Playgroud)

或者我只是这样做:

Foo *foo = [Foo new];

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

... then somewhere later use foo.aBlock()
Run Code Online (Sandbox Code Playgroud)

添加是否__strong *strongFoo = weakFoo有意义还是仅仅[weakFoo bar]在块内使用?

Alf*_*nso 5

在你的例子中,并不是必须再次在块内部进行强引用:weakFoo将是nil并且方法未被调用,或者它是有效的引用,并且在该调用的持续时间内保持有效.

但请考虑以下代码段:

Foo *foo = [Foo new];

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

... then somewhere later use foo.aBlock()
Run Code Online (Sandbox Code Playgroud)

现在你引入了竞争条件,其中weakFoo第一次调用有效,但nil第二次调用有效.这几乎不是你想要的.在这种情况下__strong Foo *foo = weakFoo;,请确保两个调用都具有相同的值.

编辑:

以下是如何触发此类竞争条件的示例:

@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;
}
Run Code Online (Sandbox Code Playgroud)