基于 GCD 的登录超时有时会在下次尝试登录时触发



我在制定问题标题时遇到了一些麻烦,如果您有更好的选择,请进行编辑。

我有一个登录过程,我在其中添加了超时:

private func startTimeout() {
self.timeoutActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 20) { 
[weak self] in
guard let weakSelf = self else {
return
}
if weakSelf.timeoutActive && !weakSelf.loggedIn {
weakSelf.onError("Login timed out")
}
}
}

我设计了登录过程,以便如果我们出于任何原因需要再次登录(例如注销后,或者在登录过程确定缺少或错误的凭据之后(,我们最终会进入执行登录的类的同一实例。

现在,据我所知,我们永远无法阻止计划块的执行,只能通过使用一些标志来阻止它,这就是我对 timeoutActive 标志所做的。这就像一个魅力。

但是,如果第二次登录的计时恰好是为了让上一个调度块在启动新的登录进程后执行,我会遇到问题(当启动新的登录过程时,timeoutActive 标志再次设置为 true(。新登录名收到不正确的超时。

我一直在考虑解决它的不同方法,并尝试了一些,但无法让其中任何一个起作用。

我有一个想法,使用performSelectorAfterDelay代替 GCD,GCD 是可以取消的,但在 Swift 中不可用 (3(。

我还考虑过拥有一些带有被阻止块 ID 列表的唯一块 ID 的想法 - 但这似乎有点矫枉过正。

我还有一个想法,将块中的当前调度时间(.now(((与原始截止日期(.now(( + 20(进行比较,看看它是否匹配,但我不知道这个截止日期有多精确,感觉不稳定。

我剩下的唯一想法是围绕登录过程本身制作某种类似任务的对象,包括超时并为不同的登录创建该任务的新实例。似乎有点工作,如果我找到一种更简单的方法,我宁愿

。以前有没有人遇到过这种情况并有解决方案?

这就是我从丹对这个问题的评论中得出的结论:

private var timeoutBlock: DispatchWorkItem? = nil
private func startTimeout() {
self.timeoutBlock = DispatchWorkItem(block: { [weak self] in
guard let weakSelf = self else {
return
}
if !weakSelf.loggedIn {
weakSelf.onError("Login timed out")
}
})
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 20, execute: self.timeoutBlock!)
}

并在离开视图控制器或完成该过程时使用self.timeoutBlock?.cancel()。这符合预期!

最新更新