DispatchQueue.main.asyncAfter с переключателем включения/выключения

Я набросал приведенную ниже структуру, чтобы предупредить пользователя о медленном сетевом соединении.

Когда функция собирается сделать вызов серверу, она создает ResponseTimer. Это устанавливает отложенное уведомление, которое срабатывает только в том случае, если responseTimer var isOn = true. Когда моя функция получит ответ от сервера, установите responseTimer.isOn = false.

Вот структура:

struct ResponseTimer {

var isOn: Bool

init() {
    self.isOn = true
    self.setDelayedAlert()
}

func setDelayedAlert() {
    let timer = DispatchTime.now() + 8
    DispatchQueue.main.asyncAfter(deadline: timer) {
        if self.isOn {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: toastErrorNotificationKey), object: self, userInfo: ["toastErrorCase" : ToastErrorCase.poorConnection])
        }
    }
}

И вот как я бы его использовал

func getSomethingFromFirebase() {

    var responseTimer = ResponseTimer()

    ref.observeSingleEvent(of: .value, with: { snapshot in
        responseTimer.isOn = false

        //do other stuff
    })
}

Даже в тех случаях, когда ответ возвращается до завершения 8-секундной задержки, уведомление все равно срабатывает. Что я здесь делаю не так??? Есть ли лучший шаблон для чего-то подобного?

Спасибо за помощь!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
724
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Лучше использовать DispatchSourceTimer, который можно отменить.

var timer : DispatchSourceTimer?

func startTimer()
{
    if timer == nil {
        timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
        timer!.schedule(deadline: .now() + .seconds(8))
        timer!.setEventHandler {
            DispatchQueue.main.async {
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: toastErrorNotificationKey), object: self, userInfo: ["toastErrorCase" : ToastErrorCase.poorConnection])
            }
            self.timer = nil
        }
        timer!.resume()
    } 
}

func getSomethingFromFirebase() {

    startTimer()

    ref.observeSingleEvent(of: .value, with: { snapshot in
         self.timer?.cancel()
         self.timer = nil
        //do other stuff
    })
}

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

enesefuu 09.03.2019 20:06
Ответ принят как подходящий

Timer — лучший способ сделать это (зачем хранить эту отправленную задачу после того, как вы получили ответ и знаете, что она вам больше не нужна). Но я не вижу ничего выше, что могло бы вызвать поведение, которое вы описываете. Я бы посоветовал вам добавить разумное ведение журнала и / или «наблюдать» за isOn, чтобы вы могли видеть, где он устанавливается / сбрасывается.

Но реализация Timer может выглядеть так:

class ResponseTimer {
    private weak var timer: Timer?

    func schedule() {
        timer = Timer.scheduledTimer(withTimeInterval: 8, repeats: false) { _ in // if you reference `self` in this block, make sure to include `[weak self]` capture list, too
            NotificationCenter.default.post(...)
        }
    }

    func invalidate() {
        timer?.invalidate()
    }

    // you might want to make sure you `invalidate` this when it’s deallocated just in 
    // case you accidentally had path of execution that failed to call `invalidate`.

    deinit {
        invalidate()
    }
}

И тогда вы можете сделать:

func getSomethingFromFirebase() {

    var responseTimer = ResponseTimer()
    responseTimer.schedule()

    ref.observeSingleEvent(of: .value) { snapshot in
        responseTimer.invalidate()

        //do other stuff
    }
}

Другие вопросы по теме