Я использую GCD DispatchWorkItem
для отслеживания моих данных, которые отправляются в firebase.
Первое, что я делаю, это объявляю 2 свойства класса типа DispatchWorkItem
, а затем, когда я готов отправить данные в firebase, я инициализирую их значениями.
Первое свойство называется errorTask
. При инициализации он cancels
firebaseTask
и устанавливает его в nil
, а затем печатает «errorTask fired». У него есть DispatchAsync Timer
, который вызовет его через 0,0000000001 секунды, если errorTask не будет отменен до этого.
Второе свойство называется firebaseTask
. При инициализации он содержит функцию, которая отправляет данные в firebase. Если обратный вызов firebase выполнен успешно, то errorTask
отменяется и устанавливается на nil
, а затем печатается оператор печати «обратный вызов firebase был достигнут». Я также проверяю, была ли отменена задача firebaseTask.
Проблема в том, что код внутри errorTask
всегда запускается до того, как будет достигнут обратный вызов firebaseTask
. Код errorTask
отменяет firebaseTask
и устанавливает его в ноль, но по какой-то причине firebaseTask
все еще работает. Я не могу понять, почему?
Операторы печати поддерживают тот факт, что errorTask запускается первым, потому что "errorTask fired"
всегда печатается до "firebase callback was reached"
.
Почему firebaseTask не отменяется и не устанавливается на nil, даже если это происходит из-за errorTask?
В моем фактическом приложении происходит следующее: если пользователь отправляет некоторые данные в Firebase, появляется индикатор активности. После достижения обратного вызова firebase индикатор активности отключается, и пользователю отображается предупреждение о том, что он был успешным. Однако, если индикатор активности не имеет таймера и обратный вызов никогда не достигается, он будет вращаться вечно. DispatchAsyc after
имеет таймер, установленный на 15 секунд, и если обратный вызов не будет достигнут, появится метка ошибки. 9 из 10 раз всегда работает.
- отправить данные в фб
- показать индикатор активности
- обратный вызов достигнут, поэтому отмените errorTask, установите для него значение nil и отключите индикатор активности
- показать предупреждение об успехе.
Но время от времени
- это займет больше времени, чем 15 секунд
firebaseTask
отменяется и устанавливается равным нулю, а индикатор активности будет закрыт.- метка ошибки будет отображаться
- предупреждение об успехе все равно появится
Блок кода errorTask
отклоняет actiInd, показывает 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")
})
}