You need to enable JavaScript to run this app. Swift Combine下Firestore实时监听数据经Mapper转换后不更新问题求助
优惠活动
大模型
产品
解决方案
定价
更多

Swift Combine下Firestore实时监听数据经Mapper转换后不更新问题求助

问题根因

你用Future包装Firestore的addSnapshotListener是核心问题。Future是Combine里的单值发布者,只会发送一次结果就立刻进入完成状态,后续snapshotListener触发的新数据就算你调用了completion(.success(dataJson)),也不会再向下游传递了,所以自然触发不了后续的Mapper转换逻辑。

修复方案

修改GetNewsRemoteDataSource的execute方法实现,用能持续发送多值的PassthroughSubject替代单值的Future,同时要正确处理监听取消时移除Firestore的快照监听,避免内存泄漏:

public func execute(request: String?) -> AnyPublisher<[NewsResponse], Error> {
    // 创建可连续发送值的Subject
    let subject = PassthroughSubject<[NewsResponse], Error>()
    // 保存快照监听的引用,用于取消时移除监听
    var listener: ListenerRegistration?
    
    listener = Firestore.firestore().collection("news").addSnapshotListener { (querySnapshot, error) in
        if let error = error {
            // 发生错误时发送错误事件
            subject.send(completion: .failure(error))
            return
        }
        guard let documents = querySnapshot?.documents else {
            print("Document not found")
            // 没有文档时发送空数组
            subject.send([])
            return
        }
        
        let dataJson = documents.compactMap { queryDocumentSnapshot in
            try? queryDocumentSnapshot.data(as: NewsResponse.self)
        }
        // 每次快照更新都发送新数据
        subject.send(dataJson)
    }
    
    // 当订阅被取消时,自动移除Firestore快照监听
    return subject.handleEvents(receiveCancel: {
        listener?.remove()
    }).eraseToAnyPublisher()
}

额外注意事项

  1. 上游改成多值发布者后,下游订阅时不要用first()这类只取一次值的操作符,要保持订阅状态才能持续接收更新。
  2. 现有代码里Repository、DataSource、Transformer中定义的@Published存储属性如果没有特殊使用场景可以移除,直接订阅execute方法返回的Publisher处理数据流即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 09:24:03