Swift 3, 4 ve 5'te dispatch_after GCD'yi nasıl yazarım?


445

Swift 2'de, dispatch_afterbüyük merkezi sevkıyat kullanarak bir eylemi geciktirmek için kullanabildim :

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 
})

Fakat bu artık Swift 3'ten beri derlenmiyor gibi görünüyor. Bunu modern Swift'te yazmanın tercih edilen yolu nedir?


6
Geçiş süreci hakkında daha fazla bilgiyi burada bulabilirsiniz: https://swift.org/migration-guide/ "Sevkiyat" bölümü bu soru ile ilgilidir
tonik12

sorunuz olmalı UInt64mı?
Tatlım

Yanıtlar:


1126

Sözdizimi basitçe:

// to run something in 0.1 seconds

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

Not ekleme yukarıdaki sözdizimi secondsbir şekilde Double(biz NSEC ekleyerek alışmış esp beri) karmaşa kaynağı olarak görünmektedir. Yani "olarak saniye ekleyin Doubleçünkü sözdizimi eserler" deadlinebir olan DispatchTimeperde arkasında, bir var ve +bir alacak operatör Doubleve o sayıda saniye ekleyin DispatchTime:

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

Eğer gerçekten, msn us veya NSEC farklı tamsayılar eklemek istiyorsanız, DispatchTimeaynı zamanda bir ekleyebileceğiniz DispatchTimeIntervalbir etmek DispatchTime. Bu, şunları yapabileceğiniz anlamına gelir:

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")
}

Bunların hepsi +, DispatchTimesınıftaki operatör için bu ayrı aşırı yük yöntemi nedeniyle sorunsuz bir şekilde çalışır .

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

Bir kişiye gönderilen bir görevi iptal etme konusunda nasıl bir soru soruldu. Bunu yapmak için kullanın DispatchWorkItem. Örneğin, bu, beş saniye içinde başlatılacak bir görev başlatır veya görünüm denetleyicisi kapatılır ve deinityeniden konumlandırılırsa görevi iptal eder:

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() { ... }

}

'De [weak self]yakalama listesinin kullanımına dikkat edin DispatchWorkItem. Güçlü bir referans döngüsünden kaçınmak için bu gereklidir. Ayrıca, bunun önleyici bir iptal yapmadığını, ancak daha önce yapmadıysa görevin başlamasını durdurduğunu unutmayın. Ancak, cancel()çağrı ile karşılaştığında zaten başlamışsa , blok yürütmeyi tamamlar ( isCancelledbloğun içinde manuel olarak kontrol etmiyorsanız ).


5
Bunu belirttiğiniz için teşekkürler ve aslında swift.org/migration-guide bu değişikliği el ile yapma ihtiyacından bahsediyor.
matt

1
Ay pardon. Burada çok geç :). Tüm karışıklığın aslında gitmesi gerektiğini düşündü, ancak sıçramayı almadı. IMO "basit" çözüm tek gerçek çözümdür.
tobiasdm

1
@ İptal etmeyi nasıl iptal edebilirim? Teşekkürler.
kemicofa hayalet

Peki dinamik bir bekleme nasıl eklenir? Örneğin, bir izin numarası var: Float = 1.0. Ve .now () + .milliseconds (sayı) çalışmıyor. Çift (sayı) da yoktur. Ben çözemiyorum.
Kjell

2
DispatchTimeIntervalRenditions gibi .millisecondsgerektirir Int. Ama sadece saniyeler ekliyorsam Double, örneğin kullanırdım let n: Double = 1.0; queue.asyncAfter(deadline: .now() + n) { ... }.
Rob

128

Hızlı 4:

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

Defa .seconds(Int), .microseconds(Int)ve .nanoseconds(Int)de kullanılabilir.


7
.millisecondsDouble'tan daha iyidir.
DawnSong

5
Çok hoş. Diğerleri için bir not: diğer DispatchTimeIntervalnumaralandırma değerlerinden herhangi birini de kullanabilirsiniz . case seconds(Int) case milliseconds(Int) case microseconds(Int) case nanoseconds(Int)
Rob MacEachern

@RobMacEachern, teşekkürler, iyi bir öneri Cevaba ekliyorum.
Sverrisson

2
.milliseconds is better than Double. - Bunu bir tişörtde istiyorum;).
Chris Prince

58

Sadece gecikme fonksiyonunu istiyorsanız

Swift 4 ve 5

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

Aşağıdaki gibi kullanabilirsiniz:

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

DispatchQueue.main.asyncAfter (son tarih:) çalışmıyor. Üst sınıfından herhangi bir yöntemi aşırı yüklemediğini söylüyor.
Fabrizio Bartolomucci

7
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: closure)daha basit.
DawnSong

16

Swift 3 sürümünden sonra, @escaping eklenmelidir

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

5

Kabul Edilen Cevaptan biraz farklı bir lezzet.

Hızlı 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

Hızlı 4

DispatchQueue üzerinde bir uzantı oluşturabilir ve DispatchQueuedahili olarak asyncAfter işlevini kullanan işlev gecikmesi ekleyebilirsiniz.

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

ve kullan

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

2
Bunun @ rockdaswift'in cevabından farkı nedir?
brandonscript

Dediğim gibi gecikme parametresi olarak alır ve sadece performAfter (gecikme: 2) {}
Suhit Patil

Kapatma parametreleri varsayılan olarak kaçmıyor, @escaping, bir closure parametresinin kaçabileceğini gösterir. Potansiyel kilitlenmeyi kaydetmek için kapanışta @ kaçan parametre eklendi.
Suhit Patil

3

aramak DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)

Swift 3 (Düzen> Dönüştür> Geçerli Swift Sözdizimine) dönüştürmek için Xcode araçlarını kullanmanızı şiddetle tavsiye ederim. Bunu benim için yakaladı


3

Swift 4.1 ve Xcode 9.4.1'de

Basit cevap ...

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

3
Bunun kabul edilen cevaptan ne kadar farklı olduğundan emin değil misiniz?
brandonscript

3

Swift 5 ve üstü

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

1

Cevaplar hiçbiri ana olmayan bir iş parçacığı üzerinde çalışan bahsetti, bu yüzden benim 2 sent ekleyerek.

Açık ana sıranın (ana iş parçacığı)

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

VEYA

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

Genel kuyrukta (belirtilen QOS tabanlı ana iş parçacığı değil).

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

VEYA

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

0

Bu Swift 3'te benim için çalıştı

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
Bunun kabul edilen cevaptan nasıl farklı olduğundan emin değil misiniz?
brandonscript

0

Kullanabilirsiniz

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

0

bunu dene

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

Bunun etkilenen yanıttan nasıl farklı olduğundan emin değil misiniz?
brandonscript
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.