Почему в DispatchQueue.main.asyncAfter (..., операции с различной задержкой выполняются одновременно - PullRequest
0 голосов
/ 25 апреля 2020

мой код:

let operationStart = Date()

for i in 0...20 {

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(i)) {

        let distance = operationStart.distance(to: Date())

        print("operation \(i) executed after \(distance)")
    }

}

Вывод:

operation 0 executed after 0.001116037368774414
operation 1 executed after 0.5226989984512329
operation 2 executed after 1.0015490055084229

...

operation 9 executed after 4.940060019493103
operation 10 executed after 5.499879002571106
operation 11 executed after 6.049391031265259
operation 12 executed after 6.0494760274887085
operation 13 executed after 7.105716943740845
operation 14 executed after 7.105777978897095
operation 15 executed after 8.189378023147583
operation 16 executed after 8.189532995223999
operation 17 executed after 9.30673599243164
operation 18 executed after 9.306856036186218
operation 19 executed after 10.423419952392578
operation 20 executed after 10.423549056053162

как этого избежать? Мне нужно выполнять операции с равными задержками.

Ответы [ 2 ]

1 голос
/ 27 апреля 2020

Что-то, что следует учитывать при использовании asyncAfter, которое описано здесь :

Работа гарантированно будет выполнена после крайнего срока, но не обязательно в этот момент , Другими словами, это может занять больше времени, чем крайний срок, но это никогда не произойдет раньше крайнего срока.

Так что использование Timer будет более подходящим для вашего случая, как ответил @jawadAli.

1 голос
/ 25 апреля 2020

Используйте DispatchSourceTimer для этой цели, потому что, если у вас есть куча вызовов asyncAfter в будущем). При его объединении общая скорость должна оставаться в значительной степени постоянной, но она будет объединять их вместе, давая вам больше заиканий в ваших таймерах

   let operationStart = Date()
    let queue = DispatchQueue(label: "com.domain.app.timer")
    var timer = DispatchSource.makeTimerSource(queue: queue)
    var i = 0
    //for i in 0...20 {
    timer.schedule(deadline: .now(), repeating: 0.5, leeway: .seconds(0))
    timer.setEventHandler {  // `[weak self]` only needed if you reference `self` in this closure and you want to prevent strong reference cycle
        let distance = operationStart.distance(to: Date())
        i = i+1
        if i == 20 {
            timer.cancel()
        }
        print("operation \(i) executed after \(distance)")
    }

    timer.resume()

enter image description here

...