gpt4 book ai didi

iOS block - 避免循环保留

转载 作者:塔克拉玛干 更新时间:2023-11-02 09:06:36 24 4
gpt4 key购买 nike

如果我在 block 内使用 dispatch_queue 会怎样?避免保留循环又避免过早释放弱指针的正确方法是什么?

    __weak MyClass *weakSelf = self;

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

dispatch_async(dispatch_get_main_queue(), ^{
// using selfref here
}
});

这是正确的做法还是我遗漏了什么?我怎样才能确保一切都得到正确处理并且不会发生保留循环?我不能在这里做一些 dealloc 测试...

我的问题不同于this here ,因为我的第一个 block 中确实有另一个 block 。我在问如何处理这种情况。

最佳答案

首先要澄清的是,仅当对象指向自身时才会发生循环保留!这通常发生在对象的某些属性通过 block 或委托(delegate)强烈引用回对象(obj 持有属性,持有对象...)时。

Blocks 捕获对从外部范围传递给它们的任何对象的强引用 - 包括 self。当您声明一个 block 并执行它时,这不是问题,因为 block 是在方法内部声明的,而 ARC将在方法结束时释放它:

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

[self someMethod];

};

aBlock();
}

但是当您存储此 block 以供以后使用(例如回调)时会出现问题,如下所示:

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

-(void)test
{
_aBlock = ^{

[self someMethod];

};
}

我们现在在 ClassA 中有一个强引用(我们的属性 aBlock),它持有对 ClassA 的强引用(通过 aBlock 实现中的 self)。现在我们遇到了一个问题——这个类指向它自己并且永远不会被释放!如果我们将上面重写如下,则更加明显:

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

[self someMethod];

};
}

现在让我们分解您的代码,以确保我们在谈论相同的事情:

__weak MyClass *weakSelf = self;

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

dispatch_async(dispatch_get_main_queue(), ^{
// using selfref here <---- inner block
}
});

一步一步来:

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

希望这一切对你来说有意义,你会与 ObjC block 一起光荣地战斗;)

关于iOS block - 避免循环保留,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29918676/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com