我使用 GCDDispatchWorkItem来跟踪发送到 firebase 的数据。
我要做的第一件事是声明 2 个类型的类属性,DispatchWorkItem然后当我准备好将数据发送到 firebase 时,我用值初始化它们。
第一个属性名为errorTask。初始化它cancels并将firebaseTask其设置为nil然后打印“errorTaskfired”。如果DispatchAsync Timer在此之前没有取消 errorTask,它将在 0.0000000001 秒内调用它。
第二个属性名为firebaseTask。初始化时,它包含一个将数据发送到 firebase 的函数。如果 firebase 回调成功,则errorTask取消并设置为nil,然后打印一条打印语句“firebase 回调已到达”。我还检查了 firebaseTask 是否被取消。
问题是内部的代码errorTask总是在firebaseTask到达回调之前运行。errorTask代码取消并将其firebaseTask设置为 nil 但由于某种原因firebaseTask仍然运行。我想不通为什么?
print 语句支持 errorTask 先运行的事实,因为
"errorTask fired"总是在之前打印"firebase callback was reached"。
即使 errorTask 使这些事情发生,为什么 firebaseTask 没有被取消并设置为零?
在我的实际应用程序中,如果用户向 Firebase 发送一些数据,则会出现一个活动指示器。一旦达到 firebase 回调,活动指示器就会消失,并向用户显示警报,说明它是成功的。但是,如果活动指示器上没有计时器并且从未达到回调,那么它将永远旋转。将DispatchAsyc after计时器设置为 15 秒,如果未达到回调,则会显示错误标签。10 次中有 9 次总是有效。
- 发送数据到FB
- 显示活动指示器
- 回调到达所以取消errorTask,将其设置为nil,并关闭活动指示器
- 显示成功警报。
但每隔一段时间
- 这将需要更长的时间然后 15 秒
firebaseTask被取消并设置为零,活动指示器将被关闭- 错误标签将显示
- 成功警报仍会出现
代码块关闭actiInd errorTask,显示 errorLabel,取消firebaseTask并设置它为 nil。一旦 firebaseTask 被取消并设置为 nil,我认为其中的所有内容也会停止,因为回调从未到达。 这可能是我困惑的原因。似乎即使firebaseTask被取消并设置为零,someRef?.updateChildValues(...它仍在运行,我也需要取消它。
我的代码:
var errorTask:DispatchWorkItem?
var firebaseTask:DispatchWorkItem?
@IBAction func buttonPush(_ sender: UIButton) {
// 1. initialize the errorTask to cancel the firebaseTask and set it to nil
errorTask = DispatchWorkItem{ [weak self] in
self?.firebaseTask?.cancel()
self?.firebaseTask = nil
print("errorTask fired")
// present alert that there is a problem
}
// 2. if the errorTask isn't cancelled in 0.0000000001 seconds then run the code inside of it
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0000000001, execute: self.errorTask!)
// 3. initialize the firebaseTask with the function to send the data to firebase
firebaseTask = DispatchWorkItem{ [weak self] in
// 4. Check to see the if firebaseTask was cancelled and if it wasn't then run the code
if self?.firebaseTask?.isCancelled != true{
self?.sendDataToFirebase()
}
// I also tried it WITHOUT using "if firebaseTask?.isCancelled... but the same thing happens
}
// 5. immediately perform the firebaseTask
firebaseTask?.perform()
}
func sendDataToFirebase(){
let someRef = Database.database().reference().child("someRef")
someRef?.updateChildValues(myDict(), withCompletionBlock: {
(error, ref) in
// 6. if the callback to firebase is successful then cancel the errorTask and set it to nil
self.errorTask?.cancel()
self.errorTask? = nil
print("firebase callback was reached")
})
}