块中的弱引用和保留周期

时间:2012-08-06 04:11:46

标签: iphone objective-c ios

In this question,我询问了以下代码并保留了周期:

__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];

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

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:8)

我无法告诉你第二个例子中保留周期的原因,因为我不知道MBItem,但是有两种不同的使用模式。

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

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

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

如果您希望在块执行之前取消分配{strong> <{1}}, 或者如果有可能根本不会调用该块, 那么你必须使用弱引用并检查块内的值:

self

在这种情况下,块不会保留__weak MyClass *weakSelf = self; [startSomeOperationWithCompletionBlock:^{ MyClass *strongSelf = weakSelf; if (strongSelf) { [strongSelf doSomeThing]; } }]; ,因此可以释放self。在这种情况下,self会自动设置为weakSelf。因此,如果最后执行该块,则必须首先检查nil是否仍然有效。 (或者您可以使用它,因为向weakSelf发送消息是无操作。)

在块内部分配强引用nil可防止在块执行时释放strongSelf