2011-12-18 14 views
12

GCDを使ってコードブロックをバックグラウンドで定期的に実行するにはどうしたらいいですか? 私はレンダリング、物理学、ゲームロジックなどのいくつかのサブシステムを持つゲームエンジンを作成しようとしています。いくつかのタスクはイベントドリブンでなければなりませんが、物理システムのような一部のタスクはバックグラウンドで一定の時間(たとえば1/100秒後)で呼び出す必要があります。 コードのブロックを作成しましたが、このブロックをバックグラウンドで定期的に実行するにはどうすればよいですか? GCDの正しいツールはここにありますか?GCDを使ってバックグラウンドでコードブロックを定期的に実行できますか?

答えて

10

GCDディスパッチソースが必要です。サンプルコードについては、Creating a Timer Exampleを参照してください。スウィフトは

6

コメントに@mattが書いているように、このためにタイマーディスパッチソースを使用することができます。そこへの正しいアプローチについての彼の答えを見てください。後世のために

は、ここでいくつかの選択肢を持つ私のオリジナルの答えです:あなたのレンダリングコールバックで

  1. (たとえば、CADisplayLinkを使用して)、このための物理計算GCDジョブオフ火災(または次の?)フレーム。レンダリングフレームごとに複数の更新を行う必要がある場合は、そのジョブループを数回行うだけです。

  2. 次に計算が必要になるまでスリープする物理スレッドを持っています。このために別のスレッドがある場合、NSTimerはスレッドを100Hzで起動させるのに十分な解像度を持つかもしれません。 (メインスレッドでは、runloop上の他の入力ソースが速く一貫して発火するのを防ぐため、これは機能しません)。NSTimerが機能しない場合は、必要な次の物理アップデートまでの時間を計算し、あなたのスレッドを眠らせてください(例:[NSThread sleepForTimeInterval:]

  3. dispatch_afterを使用するブロックがあります。このような

何か:

dispatch_time_t next = dispatch_time(DISPATCH_TIME_NOW, 0); 
block = ^{ 
    next = dispatch_time(next, 10000000L); // increment by 10 ms 
    // do physics here 
    dispatch_after(next, queue, block); 
} 

あなたは(すなわち、それをdispatch_after呼び出す前に、あなたの次の時間が過去にあるかどうかを検出など)、コマ落ちについて少し賢くする必要があります

+0

こんにちは、返信に感謝を。私の主な目標は、物理サブシステムをレンダリングから切り離すことです。だから、二番目の答えは私の方が適していると思いますが、ブロックとGCDのソリューションがあるかどうかは疑問です。 – asdf

+0

OK。私は3番目のオプションを追加しました。 –

+1

"タイマーディスパッチソースは、定期的な時間間隔でイベントを生成します。タイマーを使用して、定期的に実行する必要がある特定のタスクを開始できます。 "それがGCDで定期的な仕事を直接サポートしているのではなく、ちょうどその文脈の中でOPは何を求めているのですか? – matt

3

あなたはGCDを使ってタイマーを作成することができます

func CreateTimerDispatchSource(interval: UInt64, leeway: UInt64, queue: dispatch_queue_t, block: dispatch_block_t) -> dispatch_source_t { 
    let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue) 
    dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), interval, leeway) 
    dispatch_source_set_event_handler(timer, block) 
    return timer; 
} 

var timer = CreateTimerDispatchSource(5*NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
    // do some serious stuff 
} 

スタートまたはタイマーを再開:

dispatch_resume(timer) 

タイマーサスペンド:

dispatch_suspend(timer) 
関連する問題