我做了这两个实用功能:
+ (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];
}
这个想法是您可以调用:
[自调度:block afterDelay:延迟];- 在特定时间后执行块
和
[自调度:block withInterval:延迟];- 定期执行一个块
好的,如果我按原样调用dispatch:withInterval:,它将在运行时产生错误,因为当程序尝试在B处执行该行时, _f的值将为nil;这反过来又发生了,因为_f在A持有对 _f 值的引用。
如果我将A更改为:
__block void (^_f)() = nil;
有了这个我强烈引用_f,所以当代码到达B时,_f的值是分配给它的最终值。这样做的问题是我正在陷入一个保留周期。
最后,我可以将A更改为:
__block void (^_f)() __weak = nil;
这应该可以解决这两个问题,但是我发现当代码到达B时, _f的值再次为零,因为在它被评估时,_f已经被释放。
我有几个问题:
- 在最后一种情况下,为什么_f会被释放?我如何告诉 ARC 至少在下一次调度调用之前保留该块?
- 编写这些函数的最佳(和 ARC 兼容)方法是什么?
谢谢你的时间。