iOS块 - 避免保留周期

swa*_*ner 2 ios objective-c-blocks retain-cycle

如果我dispatch_queue在一个街区内使用怎么办?什么是避免保留周期的正确方法,但也避免过早释放弱指针?

    __weak MyClass *weakSelf = self;

    [apiClient fetchData:^(...) {
        typeof(self) selfref = weakSelf;

        dispatch_async(dispatch_get_main_queue(), ^{
            // using selfref here
        }
    });
Run Code Online (Sandbox Code Playgroud)

这是正确的做法还是我错过了什么?如何确保正确处理所有内容并且不会发生保留周期?我不能在这里做一些dealloc测试......

我的问题与不同,因为我在第一个区块内有另一个区块.我问如何处理这种情况.

hri*_*.to 8

首先澄清一下,只有当对象指向自身时才会保留周期!这通常发生在对象的某些属性具有强引用返回对象(obj持有属性,它保存对象...)时,无论是通过块还是委托.

Blocks捕获对从外部范围传递给它们的任何对象的强引用- 包括self.当你声明一个块并且只是执行它时,这不是问题,因为块是在方法内声明的,而ARC将在方法的末尾解除它:

-(void)test
{
    void(^aBlock)() = ^{

        [self someMethod];

    };

    aBlock();
}
Run Code Online (Sandbox Code Playgroud)

但是,存储此块以供稍后使用(例如回调)时存在问题,如下所示:

@property(nonatomic, copy) void(^aBlock)();

-(void)test
{
    _aBlock = ^{

        [self someMethod];

    };
}
Run Code Online (Sandbox Code Playgroud)

我们现在在ClassA中有一个强引用(我们的属性aBlock),它对ClassA有强引用(在aBlock实现中通过self).现在我们遇到了一个问题 - 这个课程指向自己,永远不会被解除分配!如果我们重写如下,则更为明显:

-(void)test
{
    self.aBlock = ^{

        [self someMethod];

    };
}
Run Code Online (Sandbox Code Playgroud)

现在让我们打破你的代码只是为了确保我们正在谈论同样的事情:

__weak MyClass *weakSelf = self;

[apiClient fetchData:^(...) {
    typeof(self) selfref = weakSelf;  <---- outer block

    dispatch_async(dispatch_get_main_queue(), ^{
        // using selfref here   <---- inner block
    }
                   });
Run Code Online (Sandbox Code Playgroud)

一步一步走:

  1. 我们声明weakSelf,所以当在外部块中使用时,它不会存储强引用self- retainCount保持不变.
  2. 我们确保weakSelf在外部块结束时可用,通过局部强变量捕获它(如果你感兴趣为什么会发生这种情况,请注意,self既不弱也不强 - 它是不安全的).此外部强变量将在外部范围结束时取消引用.因此它只在外部块的开始处生成+1,在结束处生成-1 - 在块之外没有更改.
  3. 内部块将捕获对本地强引用(+1)的强引用,但是内部块本身在外部块中声明(将其视为变量,或者首先查看"测试"场景),因此它将被安全地解除分配在外块的尽头.释放内部块将导致对其持有的本地强变量的引用的安全dealloc,因此-1保留计数 - 再次在块范围之外没有变化.

希望这一切对你有意义,你将用ObjC块光荣地战斗;)