一方でUIScrollView
(またはその派生クラス)がスクロールしている、それがすべてのように思えるNSTimers
スクロールが終了するまでのget一時停止を実行しています。
これを回避する方法はありますか?スレッド?優先順位設定?何か?
一方でUIScrollView
(またはその派生クラス)がスクロールしている、それがすべてのように思えるNSTimers
スクロールが終了するまでのget一時停止を実行しています。
これを回避する方法はありますか?スレッド?優先順位設定?何か?
回答:
実装が簡単で簡単なソリューションは次のとおりです。
NSTimer *timer = [NSTimer timerWithTimeInterval:...
target:...
selector:....
userInfo:...
repeats:...];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
Swift3を使用している人のために
timer = Timer.scheduledTimer(timeInterval: 0.1,
target: self,
selector: aSelector,
userInfo: nil,
repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
timer = Timer(timeInterval: 0.1, target: self, selector: aSelector, userInfo: nil, repeats: true)
の代わりに、最初のコマンドとしてTimer.scheduleTimer()
ので、scheduleTimer()
実行ループのためにタイマーを追加し、次の呼び出しは、別のは、同じ実行ループになく、異なるモードで追加することです。同じ作業を2回行わないでください。
これは迅速なバージョンです。
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: aSelector, userInfo: nil, repeats: true)
NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
スクロール中にタイマーを起動する場合は、別のスレッドと別の実行ループを実行する必要があります。タイマーはイベントループの一部として処理されるため、ビューのスクロールの処理で忙しい場合は、タイマーにたどり着くことはありません。ただし、他のスレッドでタイマーを実行することによるパフォーマンス/バッテリーのペナルティは、この場合に対処する価値がない可能性があります。
誰でもSwift4を使用できます。
timer = Timer(timeInterval: 1, target: self, selector: #selector(timerUpdated), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: .common)
tl; dr runloopはスクロールを実行しているため、これ以上イベントを処理できません— runloopがタッチイベントを処理しているときにも発生するようにタイマーを手動で設定しない限り、または、別のソリューションを試して、GCDを使用してください
iOS開発者は必読です。最終的には、RunLoopを介して多くのことが実行されます。
Appleのドキュメントから派生。
実行ループは、その名前が聞こえるのと非常によく似ています。これは、スレッドが入り、着信イベントに応答してイベントハンドラーを実行するために使用するループです。
実行ループを実行するとタイマーやその他の定期的なイベントが配信されるため、そのループを回避すると、これらのイベントの配信が中断されます。この動作の典型的な例は、ループに入り、アプリケーションからイベントを繰り返し要求することによってマウストラッキングルーチンを実装するたびに発生します。コードはイベントを直接取得しているため、アプリケーションにそれらのイベントを正常にディスパッチさせるのではなく、マウストラッキングルーチンが終了してアプリケーションに制御を戻すまで、アクティブタイマーを起動できません。
これは、私たちが気付かないうちに何度も起こります。つまり、タイマーを10:10:10:00に起動するように設定しましたが、runloopは10:10:10:05までかかるイベントを実行しているため、タイマーは10:10:10:06に起動されます。
同様に、実行ループがハンドラールーチンの実行中にタイマーが起動した場合、タイマーは次回実行ループを通過するまで待機して、ハンドラールーチンを呼び出します。実行ループがまったく実行されていない場合、タイマーは起動しません。
イベントを1回だけ、または繰り返し生成するようにタイマーを構成できます。繰り返しタイマーは、実際の発火時間ではなく、スケジュールされた発火時間に基づいて自動的に再スケジュールします。たとえば、タイマーが特定の時間に起動するようにスケジュールされ、その後5秒ごとに起動する場合、実際の起動時間が遅れても、スケジュールされた起動時間は常に元の5秒の時間間隔になります。発火時間が大幅に遅れて、スケジュールされた発火時間の1つ以上を逃した場合、タイマーは、逃した時間に1回だけ発火します。失敗した期間の発火後、タイマーは次にスケジュールされた発火時間に再スケジュールされます。
できません。OSはあなたのために自分自身を変えるだけです。たとえば、ユーザーがタップすると、モードがに切り替わりますeventTracking
。ユーザーのタップが終了すると、モードはに戻りdefault
ます。特定のモードで何かを実行したい場合は、それが確実に行われるようにするのはあなた次第です。
ユーザーがスクロールしているとき、実行ループモードはになりtracking
ます。RunLoopはギアをシフトするように設計されています。モードがに設定されるとeventTracking
、タッチイベントが優先されます(CPUコアが制限されていることを思い出してください)。これは、OS設計者によるアーキテクチャ設計です。
デフォルトでは、タイマーはtracking
モードでスケジュールされていません。それらはに予定されています:
タイマーを作成し、デフォルトモードの現在の実行ループでスケジュールし ます。
scheduledTimer
下には、この処理を行います。
RunLoop.main.add(timer, forMode: .default)
スクロール時にタイマーを機能させたい場合は、次のいずれかを実行する必要があります。
let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self,
selector: #selector(fireTimer), userInfo: nil, repeats: true) // sets it on `.default` mode
RunLoop.main.add(timer, forMode: .tracking) // AND Do this
または単に行う:
RunLoop.main.add(timer, forMode: .common)
最終的に上記のいずれかを実行すると、スレッドがタッチイベントによってブロックされなくなります。これは次と同等です:
RunLoop.main.add(timer, forMode: .default)
RunLoop.main.add(timer, forMode: .eventTracking)
RunLoop.main.add(timer, forMode: .modal) // This is more of a macOS thing for when you have a modal panel showing.
タイマーにGCDを使用することを検討してください。これは、実行ループ管理の問題からコードを「保護」するのに役立ちます。
繰り返さない場合は、次を使用してください。
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// your code here
}
タイマーを繰り返すには、以下を使用します。
Daniel Jalkutとの話し合いからさらに深く掘り下げます:
質問:バックグラウンドスレッドのasyncAfterなどのGCD(バックグラウンドスレッド)は、RunLoopの外部でどのように実行されますか?これからの私の理解は、すべてがRunLoop内で実行されることであるということです
必ずしもそうとは限りません。すべてのスレッドには最大で1つの実行ループがありますが、スレッドの実行「所有権」を調整する理由がない場合はゼロにすることができます。
スレッドはOSレベルのアフォーダンスであり、プロセスが複数の並列実行コンテキスト間で機能を分割できるようにします。実行ループはフレームワークレベルのアフォーダンスであり、単一のスレッドをさらに分割して、複数のコードパスで効率的に共有できるようにします。
通常、スレッドで実行されるものをディスパッチする場合、何かが呼び出されない限り、おそらく実行ループはありません。 [NSRunLoop currentRunLoop]
暗黙的に作成される。
一言で言えば、モードは基本的に入力とタイマーのフィルターメカニズムです