You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:11:03