DispatchQueue.main.asyncAfter 与 on/off 开关
DispatchQueue.main.asyncAfter with on/off switch
我创建了以下结构,作为在网络连接速度较慢时提醒用户的一种方式。
当一个函数要调用服务器时,它会创建一个 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
})
}
有几种方法:
invalidate
一个Timer
在deinit
其实现可能如下所示:
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
// do something
}
}
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()
}
}
然后你可以做:
var responseTimer: ResponseTimer?
func getSomethingFromFirebase() {
responseTimer = ResponseTimer()
responseTimer.schedule()
ref.observeSingleEvent(of: .value) { snapshot in
responseTimer?.invalidate()
//do other stuff
}
}
将 asyncAfter
与 DispatchWorkItem
结合使用,您可以 cancel
:
class ResponseTimer {
private var item: DispatchWorkItem?
func schedule() {
item = DispatchWorkItem { // [weak self] in // if you reference `self` in this block, uncomment this `[weak self]` capture list, too
// do something
}
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!)
}
func invalidate() {
item?.cancel()
item = nil
}
deinit {
invalidate()
}
}
使用DispatchTimerSource
,超出范围时自动取消:
struct ResponseTimer {
private var timer: DispatchSourceTimer?
mutating func schedule() {
timer = DispatchSource.makeTimerSource(queue: .main)
timer?.setEventHandler { // [weak self] in // if you reference `self` in the closure, uncomment this
NotificationCenter.default.post(name: notification, object: nil)
}
timer?.schedule(deadline: .now() + 8)
timer?.activate()
}
mutating func invalidate() {
timer = nil
}
}
在所有三种模式中,当 ResponseTimer
超出范围时,计时器将被取消。
我创建了以下结构,作为在网络连接速度较慢时提醒用户的一种方式。
当一个函数要调用服务器时,它会创建一个 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
})
}
有几种方法:
invalidate
一个Timer
在deinit
其实现可能如下所示:
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 // do something } } 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() } }
然后你可以做:
var responseTimer: ResponseTimer? func getSomethingFromFirebase() { responseTimer = ResponseTimer() responseTimer.schedule() ref.observeSingleEvent(of: .value) { snapshot in responseTimer?.invalidate() //do other stuff } }
将
asyncAfter
与DispatchWorkItem
结合使用,您可以cancel
:class ResponseTimer { private var item: DispatchWorkItem? func schedule() { item = DispatchWorkItem { // [weak self] in // if you reference `self` in this block, uncomment this `[weak self]` capture list, too // do something } DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!) } func invalidate() { item?.cancel() item = nil } deinit { invalidate() } }
使用
DispatchTimerSource
,超出范围时自动取消:struct ResponseTimer { private var timer: DispatchSourceTimer? mutating func schedule() { timer = DispatchSource.makeTimerSource(queue: .main) timer?.setEventHandler { // [weak self] in // if you reference `self` in the closure, uncomment this NotificationCenter.default.post(name: notification, object: nil) } timer?.schedule(deadline: .now() + 8) timer?.activate() } mutating func invalidate() { timer = nil } }
在所有三种模式中,当 ResponseTimer
超出范围时,计时器将被取消。