高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QA1385
NSTimers and Rendering Loops

Q: NSTimer を使用して、Cocoa OpenGL アプリケーションの描画ループを作動させることはできますか?

A:できます。ただし、これを行うときに留意すべきことが 2 つあります。描画ループを酷使しないことが肝要です。非常に短い間隔(0.001 または 1000fps など)でタイマを作成すると、描画ループが直前の実行を完了していなくても、アプリケーションはタイマを発行するだけで多くの CPU 時間を消費します。これがもたらす実質的な影響は性能に関する問題であり、その程度は、描画ループの処理量と、マシンがタイマを作動させる速度によって中程度から重度になります。1 つ重要なことは、描画を垂直リフレッシュレートに固定すると、描画ループの反復数(すなわち、1 秒あたりのフレーム数)が画面のリフレッシュレートを超えないということです。このため、描画を垂直リフレッシュレートに同期させている場合は、タイマをリフレッシュレートより長い間隔に設定すると、さらに CPU 時間を消費するだけで、目に見えるメリットはまったくありません。原則として、ほとんどのアプリケーションでは 1 秒あたり 30 〜 60 フレームが妥当なフレームレートであるため、最初はこの範囲のフレームレートになるようなタイマ設定がよいでしょう。

Cocoa アプリケーションに関しては、タイマから直接呼び出すのではなく、描画する必要があるときにシステムに -drawRect: メッセージを送信させるのが適切な方法です。この方法では、AppKit は正しいレンダリングに必要な処理を自動的に実行できます。すなわち、-drawRect: を呼び出す前にビューにフォーカスを固定し、ビューが返ってきたら固定解除します。アニメーションと描画の結合を避けることについては、ビューの再描画(AppKit による -drawRect: の呼び出し)がタイマの送信以外の理由(ウインドウのリサイズなど)で起こる可能性があることに留意してください。アニメーションの更新を実行する場所(-drawRect: メソッド、タイマコールバックなど)に関係なく、一定の間隔で呼び出されていると考えるのはあまり安全ではありません。最も良い方法は、各フレームの開始時に時間をチェックして(この場合は CFAbsoluteTimeGetCurrent())、現在の時間と前のフレームの開始時間を比較し、その差を利用してシミュレーションをどの程度進めるか判断することです。

リスト 1: サンプルの描画ループタイマ

// タイマを -awakeFromNib に置くことで、最初から開始できる
-(void)awakeFromNib
{
    // レンダリングループタイマを作成する
    renderTimer = [[NSTimer scheduledTimerWithTimeInterval:
           0.1                                                 // 100ms 時間間隔
           target:self                                      // ターゲットはこのオブジェクト
           selector:@selector(timerFired:)       // どの関数を呼び出すか
           userInfo:nil repeats:YES]                // ユーザ情報なし / 無限に繰り返す
           retain];                                          // 自動リリースなし
}

// タイマコールバックメソッド
- (void)timerFired:(id)sender
{
  // ここで実行するのは、ディスプレイにリフレッシュが必要であることを指示することのみ
    [self setNeedsDisplay:YES];
}

ドキュメントの改訂履歴

日付メモ
2004-10-04初版

掲載日: 2004-10-04