1. ホーム
  2. ios

[解決済み] Swift 3, 4, 5 で dispatch_after GCD を書くにはどうしたらいいですか?

2022-03-21 21:17:08

質問

Swift2において、私は 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でこれを書くには、どのような方法が望ましいのでしょうか?

どのように解決するのですか?

構文は簡単です。

// to run something in 0.1 seconds

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


なお、上記の構文で seconds として Double が混乱の元になっているようです(特に私たちはnsecを追加することに慣れていたので)。その "秒を追加するとして Double という構文が機能するのは deadlineDispatchTime と、その裏側には + 演算子で Double に、その秒数を加算します。 DispatchTime :

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

しかし、どうしてもmsec、μs、nsecの整数を追加したい場合は DispatchTime を追加することもできます。 DispatchTimeIntervalDispatchTime . ということは、できるんです。

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 を使用します)。