次の 2 つのユーティリティ関数を作成しました。
+ (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:遅延]; - 特定の時間後に実行されるブロックを取得する
と
[自己ディスパッチ:ブロック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の値が再びnilになることがわかりました。これは、評価される時点で、_fが既に割り当て解除されているためです。
いくつか質問があります。
- 最後のシナリオで、 _fの割り当てが解除されるのはなぜですか? 少なくとも次のディスパッチ呼び出しまでブロックを保持するように ARC に指示するにはどうすればよいですか?
- これらの関数を記述するための最良の (および ARC 準拠の) 方法は何でしょうか?
御時間ありがとうございます。