5

在这个问题中,我询问了以下代码和保留周期:

__weak Cell *weakSelf = self;
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        UIImage *image = /* render some image */
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [weakSelf setImageViewImage:image];
        }];
    }];
    [self.renderQueue addOperation:op];

所有答案都表明这里没有必要使用弱引用,因为此代码不会导致保留周期。但是,在尝试更多代码时,以下确实会导致保留周期(如果我不使用弱引用,则不会释放当前视图控制器)

    //__weak ViewController *weakSelf = self;
    MBItem *close = [[MBItem alloc] initWithBlock:^{
        [self dismissModalWithDefaultAnimation:NO];
    }];
    NSMutableArray *items = [[NSMutableArray alloc] initWithObjects:close, nil];
    [self.childObject setItems:items];

为什么第二个会导致保留周期而不是第一个?

4

2 回答 2

12

如果您不使用,__weak您的旧代码会创建此保留周期:

  • (NSBlockOperation *)op保留外部块
  • 外部块保留self(如果您不使用__weak
  • self保留(NSOperationQueue *)renderQueue
  • (NSOperationQueue *)renderQueue保留(NSBlockOperation *)op

除非其中一个链接断开,否则该循环中的任何对象都不能被释放。但是您向我们展示的代码确实打破了保留周期。当op完成执行时,renderQueue释放它,打破保留周期。

我怀疑您的新代码会创建此保留周期:

  • (MBItem *)close保留块
  • 块保留self
  • self保留childObject
  • childObject保留(NSMutableArray *)items
  • (NSMutableArray *)items保留(MBItem *)close

如果没有任何事情破坏这些链接之一,则循环中的任何对象都不能被释放。您没有向我们展示任何破坏保留周期的代码。如果没有事件明确打破它(例如通过清除 out childObject.items),那么您需要使用__weak来打破保留周期。

于 2012-08-06T06:15:09.737 回答
8

我无法告诉您第二个示例中保留循环的原因,因为我不知道MBItem,但是块有两种不同的使用模式。

如果您希望您的块在任何情况下都能执行,那么您可以self在块中使用:

[startSomeOperationWithCompletionBlock:^{
    [self doSomeThing];
}];

该块保留对 的引用self,因此self在执行块之前不会释放它。但是在块执行之后,这个引用(和保留周期)就消失了。

如果您可能希望在块执行之前self释放它,或者如果块可能根本不会被调用,那么您必须使用弱引用并检查块内的值:

__weak MyClass *weakSelf = self;
[startSomeOperationWithCompletionBlock:^{
    MyClass *strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doSomeThing];
    }
}];

在这种情况下,该块不会保留self,因此self可以释放。在这种情况下,weakSelf设置为nil自动。因此,如果该块最终执行,您必须先检查是否weakSelf仍然有效。(或者你可以直接使用它,因为发送消息nil是无操作的。)

在块内分配强引用strongSelf可防止self在块执行时被释放。

于 2012-08-06T05:15:20.210 回答