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

iOS新构建App自动登录时数据库快照循环次数异常过高问题

问题根因分析
  • 观察者移除逻辑存在时序漏洞:现有代码的移除观察者逻辑放在DispatchQueue.main.asyncAfter(deadline: .now() + 2)延迟2秒执行的块中,新构建安装首次启动属于冷启动场景,数据加载耗时远高于登出再登录的热启动场景,2秒的延迟足够refArtists2的.value观察者被触发多次。每次触发都会新建GeoFire查询、新增keyEntered/keyExited观察者,重复进入observeReady遍历逻辑,最终导致man打印次数远超预期。
  • 新构建安装场景的本地缓存与状态残留差异:登出再登录场景下,用户的本地数据库缓存、观察者实例都会随登出逻辑被清空重置,首次触发快照回调时不会有残留的观察者和重复回调。但保持登录状态重新打包安装时,iOS系统会保留App的本地钥匙串、Firebase Realtime Database本地持久化缓存,旧版本的观察者不会随App覆盖安装自动移除;新安装的App启动后会先拉取本地缓存触发一次快照回调,再拉取服务端最新数据触发第二次回调,叠加延迟移除漏洞,就会出现多次重复遍历。
  • 观察者绑定对象错误:现有代码调用removeObserver时使用的是self.ref,但handle1和handle2是绑定在self.query1(GeoFire查询实例)上的,并非绑定在self.ref上,因此这两个观察者从未被正确移除。每次快照回调都会新增两个观察者,多次回调就会导致同一个用户进入查询范围时触发多次回调,打印多次man。
修复方案
  • 提前清理旧观察者,避免重复注册:每次注册新观察者之前先移除旧的同名观察者,从根源上避免重复回调:
// 注册新观察者前先清空旧实例
if handle != 0 {
    refArtists2.removeObserver(withHandle: handle)
}
if let oldQuery = self.query1, let h1 = self.handle1, let h2 = self.handle2 {
    oldQuery.removeObserver(withHandle: h1)
    oldQuery.removeObserver(withHandle: h2)
}
// 再执行新观察者注册逻辑
handle = refArtists2.observe(DataEventType.value, with: { snapshot in
    // 原有业务逻辑
})
  • 修正观察者移除的绑定对象,删除不必要的延迟逻辑:
// 移除2秒延迟,修正观察者所属实例
DispatchQueue.main.async {
    if snapshot.exists() && !self.people.isEmpty {
        refArtists2.removeObserver(withHandle: handle)
        if let q1 = self.query1 {
            q1.removeObserver(withHandle: self.handle1)
            q1.removeObserver(withHandle: self.handle2)
        }
    }
}
  • 新增全场景的观察者清理逻辑:在页面viewWillDisappear、App退后台、用户登出等节点统一移除所有数据库观察者,避免内存泄漏和意外的重复回调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 08:06:04