Многопоточность - DispatchQueue asyncAfter задержки в Swift

Я использую следующий код для периодического вызова функции каждую секунду. Проблема в том, что задержка на самом деле составляет 1,1 секунды и со временем смещается все больше и больше, как это видно в NSLogs (и это видно и в других частях кода, кроме NSLog). Я делаю это неправильно, или мне следует использовать таймер?

private func updateTimeCode() {
    NSLog("Updating time")
    //Some more code that doesn't take time
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
        [weak self] in
            self ? .updateTimeCode()
    }
}
 019-08-06 17:15:19.713234+0530 MyApp-Swift[8299:2685215] Updating time

 2019-08-06 17:15:20.812652+0530 MyApp-Swift[8299:2685215] Updating time

 2019-08-06 17:15:21.913188+0530 MyApp-Swift[8299:2685215] Updating time

 2019-08-06 17:15:23.028814+0530 MyApp-Swift[8299:2685215] Updating time

person Deepak Sharma    schedule 06.08.2019    source источник
comment
Я не использую фоновую очередь. Это в основной очереди. Это не так?   -  person Deepak Sharma    schedule 06.08.2019
comment
Возможно, если вы выполните какое-то другое задание в основной очереди. при вызове функции могут возникнуть некоторые проблемы, поскольку доступна только одна основная очередь. Используйте класс Timer, как предложено выше.   -  person Tushar Katyal    schedule 06.08.2019
comment
Как мне запрограммировать фоновый таймер в Swift, который можно приостанавливать и возобновлять?   -  person Deepak Sharma    schedule 06.08.2019
comment
hackingwithswift.com/example- код / ​​система / timer.pause ()   -  person Tushar Katyal    schedule 06.08.2019
comment
Это лучше, но нужно найти рабочий код - medium .com / over-engineering /   -  person Deepak Sharma    schedule 06.08.2019
comment
Вы пытаетесь запустить таймер, когда приложение находится в фоновом режиме?   -  person Tushar Katyal    schedule 06.08.2019
comment
Нет, поскольку большая часть высокоприоритетной обработки выполняется в основной очереди, возможно, таймер можно запустить в фоновой очереди.   -  person Deepak Sharma    schedule 06.08.2019
comment
Таймер работает только с другим потоком / очередью. вот ответ на ваш вопрос.   -  person Tushar Katyal    schedule 06.08.2019
comment
Это не так. Требуется работа, чтобы переместить его в фоновый поток.   -  person Deepak Sharma    schedule 06.08.2019
comment
Не связано, но [weak self] бессмысленно. Закрытие GCD не вызывает циклов сохранения. Используйте DispatchSourceTimer. Это намного надежнее.   -  person vadian    schedule 06.08.2019
comment
@vadian Я согласен с тем, что блоки, отправленные в GCD, не вызывают постоянных циклов сохранения, но они по-прежнему не позволяют self освобождаться до тех пор, пока блок не будет выполнен, что может быть или нежелательно в зависимости от ситуации. В этом конкретном случае разрешение self быть сильным будет создать цикл, потому что каждый раз, когда блок запускается, он меняет расписание, поэтому weak выполняет здесь свою работу (но согласитесь, что DispatchSourceTimer, вероятно, правильный инструмент).   -  person Rob Napier    schedule 06.08.2019
comment
@vadian просто любопытно, почему DispatchSourceTimer более надежен?   -  person Deepak Sharma    schedule 06.08.2019
comment
@RobNapier есть ли цикл сохранения, если таймер в конечном итоге останавливается?   -  person Deepak Sharma    schedule 06.08.2019
comment
@DeepakSharma Прочтите ответ Роба в stackoverflow.com / questions / 55131532 /   -  person vadian    schedule 06.08.2019
comment
@DeepakSharma Невозможно остановить вашу реализацию таймера. Но если бы это было так, это зависело бы от реализации, удаляет ли она цикл сохранения.   -  person Rob Napier    schedule 06.08.2019
comment
@RobNapier Я имел в виду, устанавливая таймер? .Invalidate () & timer = nil, не удалит ли это цикл сохранения?   -  person Deepak Sharma    schedule 07.08.2019
comment
@DeepakSharma о, это нарушит цикл сохранения для таймера. Я думал, вы имели в виду свою реализацию asyncAfter.   -  person Rob Napier    schedule 07.08.2019


Ответы (1)


Это из-за того, что вы говорите еще какой-то код, не относящийся к делу, отнимая время. Они требуют времени, и время проходит между каждым вызовом asyncAfter, поэтому в основном .now() становится чем-то большим, чем ровно 1 секунду назад.

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

person Yusuf Kamil AK    schedule 06.08.2019