回答:
UIスレッドから呼び出された場合にプログラムをロックするスリープの代わりに、NSTimer
またはディスパッチタイマーの使用を検討してください。
ただし、現在のスレッドで本当に遅延が必要な場合:
do {
sleep(4)
}
これは、sleep
UNIX の機能を使用します。
スリープが実行されるスレッドが他の作業をブロックされるため、dispatch_after
ブロックを使用する方がほとんどの場合よりも優れsleep(time)
ています。dispatch_after
作業中のスレッドを使用すると、ブロックされないため、その間に他の作業を実行できます。
アプリケーションのメインスレッドで作業している場合、sleep(time)
その間はUIが応答しないため、使用するとアプリのユーザーエクスペリエンスが低下します。
ディスパッチ後は、スレッドを凍結する代わりに、コードブロックの実行をスケジュールします。
let seconds = 4.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
// Put your code which should be executed with a delay here
}
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
// Put your code which should be executed with a delay here
}
.now() + .seconds(4)
はエラーが発生していました:expression type is ambiguous without more context
.now() + .seconds(5)
する必要はもうありません.now() + 5
Swift 3.0でのさまざまなアプローチの比較
1.睡眠
このメソッドにはコールバックがありません。この行の直後にコードを配置すると、4秒で実行されます。時間がなくなるまで、ユーザーがテストボタンなどのUI要素を反復処理するのを停止します。ボタンはスリープ状態になるとフリーズしますが、アクティビティインジケーターなどの他の要素はフリーズせずに回転しています。睡眠中にこのアクションを再びトリガーすることはできません。
sleep(4)
print("done")//Do stuff here
2.ディスパッチ、実行、タイマー
これらの3つのメソッドは同様に機能します。これらはすべて、コールバックを使用してバックグラウンドスレッドで実行されますが、構文と機能がわずかに異なります。
ディスパッチは通常、バックグラウンドスレッドで何かを実行するために使用されます。関数呼び出しの一部としてコールバックがあります
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
print("done")
})
実行は、実際には単純化されたタイマーです。遅延のあるタイマーを設定し、セレクターで関数をトリガーします。
perform(#selector(callback), with: nil, afterDelay: 4.0)
func callback() {
print("done")
}}
そして最後に、タイマーはコールバックを繰り返す機能も提供しますが、この場合は役に立ちません
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false)
func callback() {
print("done")
}}
これら3つの方法すべてについて、ボタンをクリックしてトリガーしても、UIはフリーズせず、もう一度クリックすることができます。もう一度ボタンをクリックすると、別のタイマーが設定され、コールバックが2回トリガーされます。
結論として
4つの方法のいずれも、それだけでは十分に機能しません。sleep
ユーザーインタラクションが無効になるため、画面が「フリーズ」しますが(実際には)、ユーザーエクスペリエンスが低下します。他の3つのメソッドは画面をフリーズしませんが、それらを複数回トリガーできます。ほとんどの場合、コールバックが返されるまで待ってから、ユーザーが再びコールを発信できるようにします。
したがって、より優れた設計は、3つの非同期メソッドのいずれかと画面ブロックを使用することです。ユーザーがボタンをクリックするときは、画面全体を半透明のビューで覆い、上部に回転アクティビティインジケーターを表示して、ボタンクリックが処理されていることをユーザーに伝えます。次に、コールバック関数のビューとインジケーターを削除し、アクションが適切に処理されたことをユーザーに通知します。
@objc
いるため、perform(...)
オプションのコールバック関数の前に追加する必要があります。このように:@objc func callback() {
ここで使用することdispatch_after
は良い選択であるとPalleに同意します。しかし、GCDの呼び出しは非常に煩わしいため、おそらくGCDの呼び出しは気に入らないでしょう。代わりに、この便利なヘルパーを追加できます。
public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
let dispatchTime = DispatchTime.now() + seconds
dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}
public enum DispatchLevel {
case main, userInteractive, userInitiated, utility, background
var dispatchQueue: DispatchQueue {
switch self {
case .main: return DispatchQueue.main
case .userInteractive: return DispatchQueue.global(qos: .userInteractive)
case .userInitiated: return DispatchQueue.global(qos: .userInitiated)
case .utility: return DispatchQueue.global(qos: .utility)
case .background: return DispatchQueue.global(qos: .background)
}
}
}
これで、次のようなバックグラウンドスレッドでコードを遅延させるだけです。
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
メインスレッドでのコードの遅延はさらに簡単です。
delay(bySeconds: 1.5) {
// delayed code, by default run in main thread
}
さらに便利な機能を備えたフレームワークを好む場合は、HandySwiftをチェックアウトしてください。CarthageまたはAccioを介してプロジェクトに追加し、上記の例とまったく同じように使用できます。
import HandySwift
delay(by: .seconds(1.5)) {
// delayed code
}
DispatchTime
あり、Swift 2では利用できなかったため、以前は型変換が必要でしたlet dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
。
Swift 4.2およびXcode 10.1
合計4つの遅延方法があります。これらのオプションのうち、しばらくしてから関数を呼び出したり実行したりする場合は、1をお勧めします。睡眠()は、使用時に少なくともケースです。
オプション1。
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
self.yourFuncHere()
}
//Your function here
func yourFuncHere() {
}
オプション2。
perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)
//Your function here
@objc func yourFuncHere2() {
print("this is...")
}
オプション3。
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)
//Your function here
@objc func yourFuncHere3() {
}
オプション4。
sleep(5)
何かを実行するためにしばらくしてから関数を呼び出したい場合は、sleepを使用しないでください。
@nneonneoの答えは、使用を提案しましたNSTimer
が、その方法を示していませんでした。これは基本的な構文です:
let delay = 0.5 // time in seconds
NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(myFunctionName), userInfo: nil, repeats: false)
これは、それがどのように使用されるかを示す非常に単純なプロジェクトです。ボタンが押されると、0.5秒の遅延後に関数を呼び出すタイマーが起動します。
import UIKit
class ViewController: UIViewController {
var timer = NSTimer()
let delay = 0.5
// start timer when button is tapped
@IBAction func startTimerButtonTapped(sender: UIButton) {
// cancel the timer in case the button is tapped multiple times
timer.invalidate()
// start the timer
timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
}
// function to be called after the delay
func delayedAction() {
print("action has started")
}
}
使用すると、dispatch_time
(のようにPalleの回答)別の有効なオプションです。ただし、キャンセルは困難です。を使用NSTimer
すると、遅延したイベントが発生する前にキャンセルするには、次を呼び出すだけです。
timer.invalidate()
sleep
スレッドで実行されているすべての作業を停止するため、特にメインスレッドでの使用はお勧めしません。
私のより完全な答えはここを参照してください。
拡張機能を作成して、遅延機能を簡単に使用できます(構文:Swift 4.2以降)
extension UIViewController {
func delay(_ delay:Double, closure:@escaping ()->()) {
DispatchQueue.main.asyncAfter(
deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}
}
UIViewControllerでの使用方法
self.delay(0.1, closure: {
//execute code
})
コードが既にバックグラウンドスレッドで実行されている場合は、Foundationでこのメソッドを使用してスレッドを一時停止します。Thread.sleep(forTimeInterval:)
例えば:
DispatchQueue.global(qos: .userInitiated).async {
// Code is running in a background thread already so it is safe to sleep
Thread.sleep(forTimeInterval: 4.0)
}
(コードがメインスレッドで実行されているときの提案については、他の回答を参照してください。)
単純な時間遅延を作成するには、Darwinをインポートしてから、sleep(seconds)を使用して遅延を実行します。ただし、この処理には数秒しかかかりません。したがって、より正確な測定を行うには、Darwinをインポートし、usleep(100万分の1秒)を使用して非常に正確な測定を行うことができます。これをテストするために、私は書きました:
import Darwin
print("This is one.")
sleep(1)
print("This is two.")
usleep(400000)
print("This is three.")
印刷してから1秒待ってから印刷し、0.4秒待ってから印刷します。すべてが期待どおりに機能しました。
これは最も簡単です
delay(0.3, closure: {
// put her any code you want to fire it with delay
button.removeFromSuperview()
})