我们将Firebase DB与RxSwift一起使用,并且遇到了交易问题。我不认为它们与RxSwift的组合有关,但这是我们的背景。
我在Firebase DB中观察数据是否有任何值更改:
let child = dbReference.child(uniqueId)
let dbObserverHandle = child.observe(.value, with: { snapshot -> () in
guard snapshot.exists() else {
log.error("empty snapshot - child not found in database")
observer.onError(FirebaseDatabaseConsumerError(type: .notFound))
return
}
//more checks
...
//read the data into our object
...
//finally send the object as Rx event
observer.onNext(parsedObject)
}, withCancel: { _ in
log.error("could not read from database")
observer.onError(FirebaseDatabaseConsumerError(type: .databaseFailure))
})
单独没有问题。读取并观察数据没有任何问题。数据的变化按原样传播。
只要应用程序的另一部分修改了具有事务的观察者数据,就会出现问题:
dbReference.runTransactionBlock({ (currentData: FIRMutableData) -> FIRTransactionResult in
log.debug("begin transaction to modify the observed data")
guard var ourData = currentData.value as? [String : AnyObject] else {
//seems to be nil data because data is not available yet, retry as stated in the transaction example https://firebase.google.com/docs/database/ios/read-and-write
return TransactionResult.success(withValue: currentData)
}
...
//read and modify data during the transaction
...
log.debug("complete transaction")
return FIRTransactionResult.success(withValue: currentData)
}) { error, committed, _ in
if committed {
log.debug("transaction commited")
observer(.completed)
} else {
let error = error ?? FirebaseDatabaseConsumerError(type: .databaseFailure)
log.error("transaction failed - \(error)")
observer(.error(error))
}
}
事务在第一次尝试时收到nil数据(这是你应该能够处理的事情。我们只是打电话
return TransactionResult.success(withValue: currentData)
在这种情况下。
但这会传播给上述观察者。观察者遇到“空快照 - 在数据库中找不到子”的情况,因为它收到一个空快照。
再次运行事务,更新数据并成功提交。并且观察者接收到更新数据的另一个更新,一切都很好。
我的问题:
有没有更好的方法来处理事务期间的nil-data而不是使用FIRTransactionResult.success
将其写入数据库?
这似乎是完成此事务运行并触发重新运行新数据的唯一方法,但也许我遗漏了一些东西 -
为什么我们收到空的currentData?数据显然是存在的,因为它被观察到了。
如果事务触发对该数据的所有观察者的“临时删除”,则该事务似乎无法使用该行为。
更新
放弃并重组数据以摆脱使用交易的必要性。通过不同的数据结构,我们能够同时更新数据集,而不会有数据损坏的风险。