我整理了以下结构,以在网络连接速度慢时提醒用户。

当函数要调用服务器时,它会创建一个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秒延迟完成之前响应返回的情况下,通知仍会触发。我在这里做错了什么???是否有更好的模式可用于此类情况?

谢谢您的帮助!

最佳答案

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
    }
}

08-19 08:03