alm*_*now 5 objective-c objective-c-blocks automatic-ref-counting
我已经制作了这两个实用功能:
+ (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];
}
Run Code Online (Sandbox Code Playgroud)
这个想法是你可以打电话:
[self dispatch:block afterDelay:delay ]; - 在特定时间后执行块
和
[self dispatch:block withInterval:delay ]; - 定期执行块
好了,如果我调用dispatch:withInterval : ,因为它会在运行时创建一个错误,因为当程序试图在B处执行行时,_f的值将为nil ; 而这又是因为_f保持对所述的值的基准_f在甲.
如果我将A更改为:
__block void (^_f)() = nil;
Run Code Online (Sandbox Code Playgroud)
并且我正在强烈引用_f,所以当代码到达B时,_f的值是分配给它的最终值.这个问题是我正在进入一个保留周期.
最后,我可以将A改为:
__block void (^_f)() __weak = nil;
Run Code Online (Sandbox Code Playgroud)
这应该解决这两个问题,但是我发现当代码达到B时,_f的值再次为零,因为在评估时,_f已经被释放.
我有几个问题:
谢谢你的时间.
我如何告诉 ARC 至少保留该块直到下一次调度调用?
我想说的是,通过您使用的方法__block。
问题是我陷入了保留周期。
我不明白为什么这会成为一个问题。您希望计时器无限期地触发,对吧?这意味着与之相关的对象也必须永远存在。只要您正在调度该块,它就会被 GCD 保留,但拥有额外的引用似乎并没有什么坏处。
如果在将来的某个时刻,您决定取消计时器,可以通过设置 来实现_f = nil。这将打破保留周期。
编写这些函数的最佳(且符合 ARC 标准)方法是什么?
嗯,最好的方法是使用NSTimer. 但我确实认为学习如何使用 GCD很有趣。令人高兴的是,Apple 这里有一个计时器示例。
好的,但是,每次调用 _f 时,对 _f 的引用是否都会递增?
让我们看看 __block 是如何工作的。系统所做的就是在堆上创建一个全局变量,并将对该内存的引用(例如,值为 A 的指针)传递到您的块(例如,位于内存值 B 处)。
因此,地址 A 处的一些内存引用地址 B 处的内存,反之亦然。如您所见,这里每个对象的保留计数为 1;好吧,GCD 也保留,但是这个保留计数是恒定的,没有理由增加。
您可以_f从其他地方为 null,然后在 GCD 完成该块后,保留计数将变为 0。
为什么当我使用 __weak 时它会被释放?
正如我们所看到的,有两件事会影响地址 B 处对象的 ARC 计数:GCD 和变量_f。如果你设置为_fweak,那么在分配给它之后,你的块仍然没有来自_fB行的保留计数,并且它没有来自B行的计数,因为你还没有实际运行该块。因此它会立即被释放。
笔记。 这就是 ARC 的美妙之处:每次你都会得到这种行为,在这里我们可以逻辑地跟踪所有发生的事情并推断出原因。使用垃圾收集器时,该块有时会被释放,有时则不会,这使得调试这个问题变得非常困难。
| 归档时间: |
|
| 查看次数: |
588 次 |
| 最近记录: |