Я набросал приведенную ниже структуру, чтобы предупредить пользователя о медленном сетевом соединении.
Когда функция собирается сделать вызов серверу, она создает 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-секундной задержки, уведомление все равно срабатывает. Что я здесь делаю не так??? Есть ли лучший шаблон для чего-то подобного?
Спасибо за помощь!





Лучше использовать 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
})
}
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
}
}
Это тоже работает. Я пометил другой ответ как ответ только потому, что он обертывает класс, что мне было нужно для параллельных вызовов сервера. Спасибо за помощь!