gpt4 book ai didi

objective-c - 递归 block 中的 ARC 行为

转载 作者:太空狗 更新时间:2023-10-30 03:51:50 29 4
gpt4 key购买 nike

我做了这两个实用函数:

+ (void)dispatch:(void (^)())f afterDelay:(float)delay {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay*NSEC_PER_SEC)),
dispatch_get_main_queue(),
f);
}

+ (void)dispatch:(void (^)())f withInterval:(float)delay {
void (^_f)() = nil; // <-- A
_f = ^{
f();
[self dispatch:_f afterDelay:delay]; // <-- B
};
[self dispatch:_f afterDelay:delay];
}

这个想法是你可以调用:

[自调度:阻止 afterDelay:延迟]; - 在特定时间后执行 block

[自调度: block withInterval:延迟]; - 定期执行 block

现在好了,如果我按原样调用 dispatch:withInterval:,它会在运行时产生一个错误,因为当程序试图执行 B 处的行时_f 的值将为 nil;而这又会发生,因为 _f 持有对 _fA 的值的引用。

如果我将 A 更改为:

,则可以解决此问题:
__block void (^_f)() = nil;

我正在对 _f 进行强引用,因此当代码到达 B 时,_f 的值就是最终值分配给它的值。这样做的问题是我陷入了保留周期。

最后,我可以将 A 更改为:

__block void (^_f)() __weak = nil;

并且应该处理这两个问题,但是我发现当代码到达B时,_f的值又是nil 因为在它被评估时,_f 已经被释放。

我有几个问题:

  • 在最后一种情况下,为什么 _f 会被释放?我如何告诉 ARC 至少在下一次调度调用之前保留该 block ?
  • 编写这些函数的最佳(并且符合 ARC)方法是什么?

感谢您的宝贵时间。

最佳答案

How do I tell ARC to retain the block at least until the next dispatch call?

我会说,通过您使用 __block 的方法。

The problem with this is that I'm incurring into a retain cycle.

我不明白为什么这会成为问题。你想让你的计时器无限期地触发,对吧?这意味着与之关联的对象也必须永远存在。只要您要分派(dispatch)该 block ,GCD 无论如何都会保留它,但拥有一个额外的引用似乎并没有什么坏处。

如果在未来的某个时候,您决定取消计时器,您可以通过设置 _f = nil 来实现。这将打破保留周期。

What would be the best (and ARC-compliant) way to write these functions?

嗯,最好的方法是使用 NSTimer。但我确实认为学习如何使用 GCD 很有趣。令人高兴的是,苹果有 a timer example here .

Ok but, doesn't the reference to _f get incremented each time _f is called?

让我们来看看 __block 是如何工作的。系统所做的是在堆上创建一个全局变量,并将指向该内存的引用(例如,一个值为 A 的指针)传递给您的 block (例如,位于内存值 B)。

因此,您在地址 A 处有一些内存引用地址 B 处的内存,反之亦然。如您所见,这里每个对象的保留计数为 1;好吧,GCD 也保留了,但是这个保留计数是恒定的,没有理由增加。

您可以从其他地方为 null _f,然后在 GCD 完成该 block 后,保留计数变为 0。

why does it get deallocated when I use __weak?

正如我们所见,有两件事会影响地址 B 处对象的 ARC 计数:GCD 和变量 _f。如果你使 _f 变弱,那么在分配给它之后,你的 block 仍然没有来自 _f 的保留计数,并且它没有来自 B 行的计数,因为你实际上没有运行 block 。因此它会立即被释放。


注意。这就是 ARC 的美妙之处:你每次都会得到这种行为,在这里我们可以逻辑地跟踪所有发生的事情并推断出原因。使用垃圾收集器,这个 block 有时会被释放,有时不会,使调试这个问题变得非常困难。

关于objective-c - 递归 block 中的 ARC 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19622754/

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