如果我将类Foo声明为:
,该怎么办?@interface Foo : NSObject
@property (copy, nonatomic) void (^aBlock)(void);
- (void)bar;
@end
@implementation Foo
- (void)bar {}
@end
我在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()
或者我只是这样做:
Foo *foo = [Foo new];
__weak Foo *weakFoo = foo;
foo.aBlock = ^{
[weakFoo bar];
}
... then somewhere later use foo.aBlock()
添加__strong *strongFoo = weakFoo
是否有意义,或仅仅在块中使用[weakFoo bar]
是否足够?
答案 0 :(得分:5)
在您的示例中,并非绝对有必要再次在块内强化引用:weakFoo
将为nil
且方法未被调用,或者它是&#39; sa有效参考,并将在此通话期间保持有效。
但请考虑以下代码段:
Foo *foo = [Foo new];
__weak Foo *weakFoo = foo;
foo.aBlock = ^{
[weakFoo bar];
[weakFoo baz];
}
... then somewhere later use foo.aBlock()
现在您引入了竞争条件,其中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;
}
答案 1 :(得分:2)
您应该使用:
__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];
}
}
答案 2 :(得分:1)
有一个原因。问题是,__weak
引用不会在块期间使对象保持活动。因此,例如,如果您有一个异步块,weakSelf
可能会在块的执行中途消失(因为弱引用不会使对象保持活动状态)。所以我们在块中使用strongSelf
来确保对象足够长,以便在块中一直使用它。