块中的弱引用和保留周期

Sno*_*man 5 iphone objective-c ios

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

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

所有答案都指出在这里使用弱引用不是必需的,因为此代码不会导致保留周期.但是,在尝试更多代码时,以下操作会导致保留周期(如果我不使用弱引用,则不会释放当前视图控制器)

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

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

rob*_*off 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用来打破保留周期.


Mar*_*n R 8

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

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

[startSomeOperationWithCompletionBlock:^{
    [self doSomeThing];
}];
Run Code Online (Sandbox Code Playgroud)

该块保留对该引用的引用self,因此self在执行该块之前不会释放该引用.但是块执行后,此引用(以及保留周期)消失了.

如果您可能希望执行块之前self取消分配,或者可能根本不调用该块,则必须使用弱引用并检查块内的值:

__weak MyClass *weakSelf = self;
[startSomeOperationWithCompletionBlock:^{
    MyClass *strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doSomeThing];
    }
}];
Run Code Online (Sandbox Code Playgroud)

self在这种情况下,块不会保留,因此self可以取消分配.在这种情况下,weakSelf设置为nil自动.因此,如果最后执行该块,则必须首先检查是否weakSelf仍然有效.(或者您可以使用它,因为发送消息nil是无操作.)

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