我整理了以下结构,以在网络连接速度慢时提醒用户。
当函数要调用服务器时,它会创建一个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秒延迟完成之前响应又回来了,通知仍会触发。我在这里做错了什么???是否有更好的模式可用于此类情况?
感谢您的帮助!
答案 0 :(得分: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
})
}
答案 1 :(得分:2)
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
}
}