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

iOS中Firebase Firestore的set与update操作失效问题求助

问题分析与修复方案

核心问题

  1. 冗余的快照监听器嵌套
    每次调用emitSingleTripLocation都会给tripRef新增快照监听器,导致:
  • 大量重复监听器堆积,占用资源
  • 监听器回调异步执行,3秒一次的定时器会触发多个未完成的更新请求,逻辑混乱
  • 监听器回调内再执行setData属于冗余操作,完全不需要先监听快照再更新
  1. 空requestId的隐性问题
    requestId默认值为空字符串,若LocalDB.shared.currentTripDetail?.acceptedRequestId为nil,你会尝试更新ID为空的无效文档,Firestore不会报错,但数据不会写入到目标位置。

  2. 异步操作与定时器的冲突
    3秒一次的定时器会频繁触发更新,而Firestore写入是异步的,前一次请求未完成时新请求可能被中断或覆盖,导致数据未同步。

修复后代码

var singleTripLocationTimer: Timer?

// 保留定时器初始化逻辑,注意在页面销毁或停止更新时调用singleTripLocationTimer?.invalidate()
if singleTripLocationTimer == nil {
    singleTripLocationTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true, block: { (timer) in
        if MySocketManager.shared.currentEmitType == .singleTripLocation {
            self.emitSingleTripLocation()
        }
    })
}

private func emitSingleTripLocation() {
    guard let currentLocation = AppLocationManager.shared.locationManager.location else {
        print("当前位置为空,跳过更新")
        return
    }
    guard let authId = LocalDB.shared.driverDetails?.id else {
        print("司机ID为空,跳过更新")
        return
    }
    guard let requestId = LocalDB.shared.currentTripDetail?.acceptedRequestId, !requestId.isEmpty else {
        print("请求ID为空,跳过更新")
        return
    }
    
    let heading = AppLocationManager.shared.currentHeading?.trueHeading ?? currentLocation.course
    var jsonObject = [String:Any]()
    jsonObject["lat"] = currentLocation.coordinate.latitude
    jsonObject["lng"] = currentLocation.coordinate.longitude
    jsonObject["success"] = true
    
    var distArr = [[String: Any]]()
    jsonObject["distancee"] = self.getDistanceFrom(distArr)
    
    print("准备更新数据", jsonObject)
    
    // 直接执行文档更新,移除冗余的快照监听逻辑
    self.requestRef.document(requestId).setData(jsonObject, merge: true) { error in
        if let error = error {
            print("更新行程数据失败: \(error)")
            return
        }
        // 单独处理司机状态更新
        var additionalData = [String: Any]()
        additionalData["is_available"] = false
        self.ref.document(authId).updateData(additionalData) { error in
            if let error = error {
                print("更新司机状态失败: \(error)")
            }
        }
    }
}

额外优化建议

  • 定时器清理:在页面销毁或停止位置更新时,必须调用singleTripLocationTimer?.invalidate(),避免定时器持续运行消耗资源。
  • 位置防抖:可以记录上次更新的坐标,只有当位置偏移超过阈值时才触发更新,减少无意义的重复请求。
  • 错误排查:每个guard分支添加打印日志,快速定位哪一步导致更新终止。

内容的提问来源于stack exchange,提问作者Shreedharshan Msd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:42:36