Использование задержки DispatchQueue в "for in l oop" - PullRequest
0 голосов
/ 10 апреля 2020

Задача - менять цвет фона раз в секунду. Был использован "для в oop". Для задержки использовалась DispatchQueue. Все вроде бы нормально, но было замечено, что после 10 итераций цвет фона начинает меняться с задержкой в ​​2 секунды, чуть позже, через 3 секунды. Чем больше итераций, тем больше задержка. Я отобразил время в консоли (секунды), чтобы увидеть, как оно меняется. Я вижу результаты, но я не понимаю, что не так. Я выполнил задачу через таймер, проблем не было, но я хочу понять, что не так с задержкой DispatchQueue.

for i in 1...150 {

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

        self.view.backgroundColor = UIColor(red: .random(in: 0...1),
                                          green: .random(in: 0...1), 
                                           blue: .random(in: 0...1), 
                                          alpha: 1)
         print("\(ymd)")

         ymd = self.myCalendar.dateComponents([.second], from: Date())
    }
}

Консоль:

second: 21 isLeapMonth: false 
second: 21 isLeapMonth: false 
second: 22 isLeapMonth: false 
second: 23 isLeapMonth: false 
second: 24 isLeapMonth: false 
second: 25 isLeapMonth: false 
second: 26 isLeapMonth: false 
second: 27 isLeapMonth: false 
second: 28 isLeapMonth: false 
second: 29 isLeapMonth: false 
second: 30 isLeapMonth: false 
second: 32 isLeapMonth: false 
second: 33 isLeapMonth: false 
second: 33 isLeapMonth: false 
second: 35 isLeapMonth: false 
second: 35 isLeapMonth: false 
second: 37 isLeapMonth: false 
second: 37 isLeapMonth: false 
second: 39 isLeapMonth: false 
second: 39 isLeapMonth: false 
second: 41 isLeapMonth: false 
second: 41 isLeapMonth: false 
second: 44 isLeapMonth: false 
second: 44 isLeapMonth: false 
second: 44 isLeapMonth: false 
second: 47 isLeapMonth: false 
second: 47 isLeapMonth: false 
second: 47 isLeapMonth: false 
second: 50 isLeapMonth: false 
second: 50 isLeapMonth: false 
second: 50 isLeapMonth: false 
second: 54 isLeapMonth: false 
second: 54 isLeapMonth: false 
second: 54 isLeapMonth: false 
second: 57 isLeapMonth: false 
second: 57 isLeapMonth: false 
second: 57 isLeapMonth: false 
second: 57 isLeapMonth: false 
second: 1 isLeapMonth: false 
second: 1 isLeapMonth: false 
second: 1 isLeapMonth: false 
second: 1 isLeapMonth: false 
second: 6 isLeapMonth: false 
second: 6 isLeapMonth: false 
second: 6 isLeapMonth: false 
second: 6 isLeapMonth: false 
second: 6 isLeapMonth: false 
second: 11 isLeapMonth: false 
second: 11 isLeapMonth: false 
second: 11 isLeapMonth: false 
second: 11 isLeapMonth: false 
second: 11 isLeapMonth: false 
second: 17 isLeapMonth: false 
second: 17 isLeapMonth: false 
second: 17 isLeapMonth: false 
second: 17 isLeapMonth: false 
second: 17 isLeapMonth: false 

1 Ответ

2 голосов
/ 16 апреля 2020

Это результат «объединения таймера», при котором «задержка» для отправляемого блока составляет 10% задержки, максимум до одной минуты задержки. (Это скрыто в коде libdispatch .) Это функция энергосбережения, позволяющая объединять / группировать удаленные, независимо запланированные задачи для одновременного запуска, чтобы избежать ненужного раскручивания оборудования слишком много раз. Самый простой способ избежать этого объединения - использовать повторяющийся таймер:

var counter = 0

Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
    counter += 1

    guard let self = self, counter <= 150 else {
        timer.invalidate()
        return
    }

    self.view.backgroundColor = UIColor(red: .random(in: 0...1),
                                      green: .random(in: 0...1),
                                       blue: .random(in: 0...1),
                                      alpha: 1)

    let ymd = self.myCalendar.dateComponents([.second], from: Date())
    print(ymd)
}

Обратите внимание на использование шаблона [weak self], чтобы таймер не сохранял постоянную ссылку на контроллер представления. И с этим оператором guard мы будем invalidate таймер, если контроллер представления отклонен.

Кстати, если вы хотите, чтобы изменение цвета было менее резким, анимируйте изменение:

var counter = 0

Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
    counter += 1
    guard let self = self, counter <= 150 else {
        timer.invalidate()
        return
    }

    UIView.animate(withDuration: 0.1) {
        self.view.backgroundColor = UIColor(red: .random(in: 0...1),
                                          green: .random(in: 0...1),
                                           blue: .random(in: 0...1),
                                          alpha: 1)
    }

    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...