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() }
额外注意事项
- 上游改成多值发布者后,下游订阅时不要用
first()这类只取一次值的操作符,要保持订阅状态才能持续接收更新。 - 现有代码里Repository、DataSource、Transformer中定义的
@Published存储属性如果没有特殊使用场景可以移除,直接订阅execute方法返回的Publisher处理数据流即可。
内容的提问来源于stack exchange,提问作者Ifadak
相关产品推荐
相关产品推荐

