タイマーを使うべき理由
これを行う正しい方法は、繰り返しタイマーを使用することです。タイマーは、毎秒特定のメソッドを繰り返し呼び出して呼び出すように構成されています。
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(updateText:)
userInfo:nil
repeats:YES];
(新しい)updateText
メソッド内で、乱数を生成してテキストを更新します。
- (void)updateText:(NSTimer *)theTimer {
int index = arc4random() % [myArray count];
myTextView.text = [myArray objectAtIndex:index];
}
これは、ほとんど自己文書化されたクリーンなソリューションです。
ループして遅延後に実行するべきではない理由。
またはを使用してこれを行うことができるのは事実ですが、間違いを犯しやすく、実際に機能するソリューションはより複雑で理解しにくいものです。performSelector:withObject:afterDelay:
dispatch_after()
特定の回数だけループして、これらのいずれかを内部で呼び出すことができると思う場合は、何か面白いものが表示されます。これらのメソッドは両方とも非同期であり、呼び出しが呼び出されるのを待ちません。彼らは単に「今」から指定された時間にそれが起こるようにスケジュールしているだけです。
非同期メソッドのループと呼び出しは何をしますか
Loop
0 |----- 1s wait -----| |update|
1 |----- 1s wait -----| |update|
2 |----- 1s wait -----| |update|
3 |----- 1s wait -----| |update|
...
----------- time --------------------->
この結果、ご想像のとおり、1秒間は何も起こりません。次に、スケジュールされたすべての通話が一度に発生します。
これは、実際には1秒後にループ全体を実行することと同じです。
|----- 1s wait -----| Loop:
0 |update|
1 |update|
2 |update|
3 |update|
...
----------- time --------------------->
代わりに、各更新後に次の呼び出しをスケジュールした場合、これを機能させることができます
|----- 1s wait -----| |update| |----- 1s wait -----| |update| ...
----------- time --------------------->
これを行うには、前の更新で次の更新をスケジュールする必要があります。
- (void)updateText {
int index = arc4random() % [myArray count];
myTextView.text = [myArray objectAtIndex:index];
[self performSelector:@selector(updateText)
withObject:nil
afterDelay:1.0];
}
これは繰り返しタイマーとまったく同じことをしますが、2つの主な欠点があります。
1)直感的ではありません。
タイマーの例では、テキストが毎秒更新されることを理解するためにタイマーコードを読むだけで済みます。この場合、を呼び出すだけupdateText
です。updateTextの実装を見ずにそのコードを読むことは、これが繰り返しのプロセスであることを直感的に理解することはできません。
2)停止したい場合は、さらに複雑になります。
NSTimer
を呼び出すだけで、へのポインタを保持して停止させることができます[myTimer invalidate];
。performSelector:...
いずれかを使用するコード、またはdispatch_after()
まだサポートしていないコード。それをサポートするように構築されている場合は、さらに複雑で直感的ではありません。