Swift 5中Firebase removeObserver失效,Observer重复执行问题求助
解决Firebase Realtime Database观察者执行两次导致数据错误的问题
问题根源
你使用observe(.value)会持续监听目标节点的所有数据变化,包括自己调用setValue修改数据后触发的更新。第一次回调执行并修改数据时,数据库的变化会再次触发观察者回调,此时handler已经完成赋值,导致第二次回调又执行了一次减1操作,最终数值被意外减了两次。
解决方案
方案1:使用单次事件监听(最简单)
如果仅需获取一次数据完成更新,不需要持续监听,直接用observeSingleEvent(of: .value)替代observe(.value),它只会触发一次回调,避免后续数据更新重复执行逻辑:
func updatePoints() { let firebaseId = UserDefaults.standard.value(forKey: "firebaseId") as? String ?? "" let reference = self.database.child("Points").child(firebaseId) reference.observeSingleEvent(of: .value, with: { snapshot in guard let userPoints = snapshot.value as? [String : Any] else { print("no points data found") return } let pointsLeft = userPoints["points_left"] as? Int ?? 0 reference.child("points_left").setValue(pointsLeft - 1) }) }
方案2:使用事务操作(更安全,适配并发场景)
如果存在多用户同时修改同一个points_left的场景,推荐使用Firebase事务操作runTransactionBlock,它能保证数据更新的原子性,彻底避免并发冲突:
func updatePoints() { let firebaseId = UserDefaults.standard.value(forKey: "firebaseId") as? String ?? "" let pointsRef = self.database.child("Points").child(firebaseId).child("points_left") pointsRef.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in var currentPoints = currentData.value as? Int ?? 0 currentPoints -= 1 currentData.value = currentPoints return TransactionResult.success(withValue: currentData) }) { (error, committed, snapshot) in if let error = error { print("事务执行失败:\(error.localizedDescription)") } } }
原代码removeObserver失效的原因
原代码中removeObserver(withHandle: handler)是在第一次回调内执行的,但此时数据库的更新还未触发第二次回调。当第二次回调触发时,handler仍处于有效状态,导致逻辑被重复执行,之后再调用removeObserver已经无法挽回数据错误。
内容的提问来源于stack exchange,提问作者Taimoor Arif
相关产品推荐
相关产品推荐

