Почему `scheduleTimer` работает правильно при установке вне блока, но не внутри блока?

Следующий фрагмент кода отлично работает при вызове вне блока завершения, но таймер никогда не срабатывает, когда я устанавливаю его внутри блока. Я не понимаю, почему есть разница

self.timer = Timer.scheduledTimer(timeInterval: 1,
                                  target: self,
                                  selector: #selector(self.foo),
                                  userInfo: nil,
                                  repeats: true)

Я не использовал ссылки на себя, когда вызывал его изначально вне блока, но потом внутри, это было необходимо. Однако я снова тестировал тот же самый код вне блока, и он все еще работает.

Блок является средством завершения, которое вызывается после запроса разрешения дляHealthKit связанная информация.

Ответы на вопрос(3)

Решение Вопроса

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

Чтобы исправить это, в этом обработчике завершения отправьте создание таймера обратно в основной поток, и он должен работать нормально:

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 см.предыдущая редакция этого ответа.

 Kevin03 июл. 2016 г., 03:21
Спасибо, имеет много смысла. Я должен был подумать об этом. Благодарю.
 Rob19 июн. 2019 г., 05:07
Если я работаю в главной очереди, я часто склоняюсь кTimer за его простоту. Однако, если таймер работает в фоновой очереди, таймер отправки является правильным инструментом.
 Honey19 июн. 2019 г., 00:01
Есть ли причина не использоватьDispatchSourceTimer а использовать только таймер?

Еще одна причина, почему 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)

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

Положите в основной поток, и, по крайней мере, у вас есть шанс на это!

 DispatchQueue.main.async {
  //insert your timer here
}

Ваш ответ на вопрос