Почему плагин `schedTimer` срабатывает должным образом при настройке вне блока, но не внутри блока?
Следующий фрагмент кода отлично работает при вызове вне блока завершения, но таймер никогда не запускается, когда я устанавливаю его внутри блока. Я не понимаю, почему есть разница:
self.timer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(self.foo),
userInfo: nil,
repeats: true)
Я не использовал собственные ссылки при вызове изначально вне блока, но затем один раз внутри, это требовалось. Однако я снова проверил один и тот же код за пределами блока, и он все еще работает.
Этот блок является обработчиком завершения, который вызывается после запроса разрешения для связанной информации HealthKit
.
Ответы
Ответ 1
Проблема в том, что рассматриваемый блок завершения, вероятно, не выполнялся в главном потоке и поэтому не имел цикла выполнения. Но таймеры должны быть запланированы в цикле выполнения, и, хотя у основного потока он есть, у большинства фоновых потоков нет (если вы сами не добавите один).
Чтобы исправить это, в этом обработчике завершения отправьте создание таймера обратно в основной поток, и он должен работать нормально:
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)
}
Или используйте таймер источника отправки (таймер, который может быть запланирован для фоновой очереди и не требует цикла выполнения).
var timer: DispatchSourceTimer!
private func startTimer() {
let queue = DispatchQueue(label: "com.domain.app.timer")
timer = DispatchSource.makeTimerSource(queue: queue)
timer.setEventHandler { [weak self] in
// do something
}
timer.schedule(deadline: .now(), repeating: 1.0)
timer.resume()
}
Синтаксис более ранней версии Swift приведен в предыдущей редакции этого ответа.
Ответ 2
Еще одна причина, почему Timer() может не работать - это то, как он создан. У меня была та же проблема, и все, что я пробовал, не решало ее, включая создание экземпляров в главном потоке. Я долго смотрел на это, пока не понял (тупо), что создаю это по-другому. Вместо Timer.scheduledTimer
Я создал его с помощью
let timer = Timer(timeInterval: 4.0, target: self, selector: #selector(self.timerCompletion), userInfo: nil, repeats: true)
В моем случае мне пришлось добавить его в цикл выполнения, чтобы запустить его. Как это
RunLoop.main.add(timer, forMode: RunLoop.Mode.default)
Ответ 3
Это может показаться очевидным, но у меня была похожая проблема, таймер просто не работал, и причина в том, что его не было в главном потоке... Никаких ошибок, просто никогда не срабатывал.
Положите в основной поток, и, по крайней мере, у вас есть шанс на это!
DispatchQueue.main.async {
//insert your timer here
}