Swift 3、4、および5でdispatch_after GCDを書き込むにはどうすればよいですか?


445

Swift 2では、dispatch_afterグランドセントラルディスパッチを使用してアクションを遅らせることができました。

var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) 
dispatch_after(dispatchTime, dispatch_get_main_queue(), { 
    // your function here 
})

しかし、これはSwift 3以降、コンパイルされなくなったようです。現代のSwiftでこれを書くための好ましい方法は何ですか?


6
移行プロセスの詳細については、https
//swift.org/migration-guide/を

あなたの質問はUInt64
ハニー

回答:


1125

構文は単純です:

// to run something in 0.1 seconds

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    // your code here
}

注、追加の上記の構文secondsとしてDouble(我々はナノ秒加えることに慣れたESPので)混乱の源であるように思われます。その「秒を追加するDouble」構文deadlineはaでDispatchTimeあり、舞台裏でa +を取り、Doubleその秒数をに追加する演算子がありますDispatchTime

public func +(time: DispatchTime, seconds: Double) -> DispatchTime

ただし、本当にmsec、μs、またはnsecの整数をに追加したい場合はDispatchTime、a DispatchTimeIntervalをに追加することもできますDispatchTime。それはあなたができることを意味します:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
    os_log("500 msec seconds later")
}

DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(1_000_000)) {
    os_log("1m μs seconds later")
}

DispatchQueue.main.asyncAfter(deadline: .now() + .nanoseconds(1_500_000_000)) {
    os_log("1.5b nsec seconds later")
}

これらはすべて+DispatchTimeクラス内のオペレーターに対するこの個別のオーバーロードメソッドのため、シームレスに機能します。

public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime

ディスパッチされたタスクをキャンセルする方法について尋ねられました。これを行うには、を使用しますDispatchWorkItem。たとえば、これは5秒で起動するタスクを開始します。または、ビューコントローラーが閉じられて割り当てが解除されるとdeinit、タスクをキャンセルします。

class ViewController: UIViewController {

    private var item: DispatchWorkItem?

    override func viewDidLoad() {
        super.viewDidLoad()

        item = DispatchWorkItem { [weak self] in
            self?.doSomething()
            self?.item = nil
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!)
    }

    deinit {
        item?.cancel()
    }

    func doSomething() { ... }

}

での[weak self]キャプチャリストの使用に注意してくださいDispatchWorkItem。これは、強い参照サイクルを回避するために不可欠です。また、これによりプリエンプティブなキャンセルは行われず、タスクがまだ開始されていない場合は、タスクの開始が停止されるだけであることに注意してください。ただし、cancel()呼び出しに遭遇するまでにすでに開始している場合、ブロックはその実行を終了します(isCancelledブロック内を手動でチェックしている場合を除く)。


5
指摘していただきありがとうございます。実際、swift.org / migration-guideは、手動で変更する必要があると述べています。
マット

1
あ、ごめんなさい。ここでは手遅れです:)。すべての混乱は実際に行くべきだと思ったが、飛躍はしなかった。IMOの「シンプルな」ソリューションは、1つの真のソリューションです。
tobiasdm 2016年

1
@ロブどうやってキャンセルするの?ありがとう。
kemicofaゴースト2016

では、動的待機をどのように追加しますか?たとえば、let番号があります。Float= 1.0です。また、.now()+ .milliseconds(number)は機能しません。Double(数値)もしません。わかりません。
Kjell、2016年

2
DispatchTimeIntervalレンディションは、のような.milliseconds必要Int。しかし、秒を追加するだけの場合Double、たとえばを使用しますlet n: Double = 1.0; queue.asyncAfter(deadline: .now() + n) { ... }
Rob

128

スウィフト4:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
   // Code
}

時間のために.seconds(Int).microseconds(Int)そして.nanoseconds(Int)使用することもできます。


7
.millisecondsダブルよりも優れています。
DawnSong 2016年

5
非常に素晴らしい。他の人への注意:他のDispatchTimeInterval列挙値も使用できます。case seconds(Int) case milliseconds(Int) case microseconds(Int) case nanoseconds(Int)
Rob MacEachern、2016年

@RobMacEachern、ありがとうございます。これを回答に追加するのは良い提案です。
スベリソン、2016年

2
.milliseconds is better than Double. -私はそれをTシャツに入れたいです;)。
Chris Prince

58

あなただけの遅延機能が必要な場合

Swift 4および5

func delay(interval: TimeInterval, closure: @escaping () -> Void) {
     DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
          closure()
     }
}

次のように使用できます。

delay(interval: 1) { 
    print("Hi!")
}

DispatchQueue.main.asyncAfter(deadline:)が機能しません。それはスーパークラスからメソッドをオーバーロードしないと言っています。
Fabrizio Bartolomucci

7
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: closure)簡単です。
DawnSong 2016年

16

Swift 3のリリース後、@ escapingも追加する必要があります

func delay(_ delay: Double, closure: @escaping () -> ()) {
  DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
    closure()
  }
}

5

受け入れられた回答のやや異なるフレーバー。

スウィフト4

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 + .milliseconds(500) + 
.microseconds(500) + .nanoseconds(1000)) {
                print("Delayed by 0.1 second + 500 milliseconds + 500 microseconds + 
                      1000 nanoseconds)")
 }

5

スウィフト4

DispatchQueueで拡張を作成し、DispatchQueue内部でasyncAfter関数を使用する関数遅延を追加できます

extension DispatchQueue {
   static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
      DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: closure)
   }
}

そして使う

DispatchQueue.delay(.milliseconds(10)) {
   print("task to be done")
}

2
これは@rockdaswiftの回答とどう違うのですか?
ブランドンスクリプト2017年

{}:私は述べたように、それをパラメータとして遅延を取るperformAfter関数内部asyncAfterをラップし、それだけperformAfter(2遅延)を使用して通話することが容易であることができる
Suhitパティル

デフォルトでは、クロージャーパラメーターはエスケープされません。@ escapingは、クロージャーパラメーターがエスケープされる可能性があることを示します。潜在的なクラッシュを保存するために、@エスケープパラメータをクロージャに追加しました。
Suhit Patil 2017

3

コール DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)

Xcodeツールを使用してSwift 3に変換することを強くお勧めします(編集>変換>現在のSwift構文に変換)。私はこれを捕まえた


3

Swift 4.1およびXcode 9.4.1の場合

簡単な答えは...

//To call function after 5 seconds time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
//Here call your function
}

3
これが受け入れられた回答とどのように違うのか分かりませんか?
ブランドンスクリプト、

3

Swift 5以降

DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
   // code to execute                 
})

1

メインスレッド以外での実行については回答がないため、2セント追加します。

上のメインキュー(メインスレッド)

let mainQueue = DispatchQueue.main
let deadline = DispatchTime.now() + .seconds(10)
mainQueue.asyncAfter(deadline: deadline) {
    // ...
}

または

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) { 
    // ...
}

上のグローバルキュー(QOSに基づく非メインスレッドは、指定されました)。

let backgroundQueue = DispatchQueue.global()
let deadline = DispatchTime.now() + .milliseconds(100)
backgroundQueue.asyncAfter(deadline: deadline, qos: .background) { 
    // ...
}

または

DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .milliseconds(100), qos: .background) {
    // ...
}

0

これはSwift 3で私のために働きました

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds


DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Sum of times: \(time1 + time2)")
}

5
これが受け入れられた回答とどのように異なるかわかりませんか?
brandonscript 2017年


0

これを試して

let when = DispatchTime.now() + 1.5
    DispatchQueue.main.asyncAfter(deadline: when) {
        //some code
    }

これが影響を受ける回答とどのように異なるのかわかりませんか?
brandonscript 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.