我使用 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")
})
}