Swiftui + Firestore + CombineLatest 不断发布数据

我正在尝试合并来自两个不同集合的查询的两个已发布对象,以使用 combineLatest 生成单个已发布数组。

import Combine
import Firebase

class FirestoreViewModel: ObservableObject {
    let userId: String
    
    @Published var aList: [DocumentA]? = nil
    @Published var bList: [DocumentB]? = nil
    
    init(userId: String,listenForChanges: Bool = false)    {
        
        // Get the user
        if (listenForChanges)   {
            self.loadA()
            self.loadB()
        }
    }
    
    var cList: AnyPublisher<[DocumentC]?,Never> {
        return Publishers.CombineLatest(
            $aList.map { (aList) -> [DocumentC]?  in
                guard let aList = aList else { return nil }
                return aList.map {a in
                    DocumentC(from: a)
                }
            },$bList.map { (bList) -> [DocumentC]?  in
                guard let bList = bList else { return nil }
                return bList.map { n in
                    DocumentC(from: b)
                }
            })
            .map { (aList,bList) -> [DocumentC]?  in
                
                if (aList == nil && bList == nil) { return nil }
                
                var cList: [DocumentC] = []
                
                if let aList = aList {
                    cList.append(contentsof: aList)
                }
                
                if let bList = bList {
                    cList.append(contentsof: bList)
                }
                return cList
            }
            .eraseToAnyPublisher()
    }
    
    private func loadA() {
        
        // Start listening
        Firestore.firestore().collection("colA").addsnapshotListener { (snapshot,error) in
            if let error = error {
                print("DEBUG: Unable to get user data: \(error.localizedDescription)")
                return
            }
            
            // Invalid data return
            guard let snapshot = snapshot else {
                print("DEBUG: null data returned")
                self.aList = nil
                return
            }
            
            // Update the info
            var aList: [DocumentA] = []
            snapshot.documents.forEach { document in
                let aData = document.data()
                guard !aData.isEmpty else {
                    return
                }
                aList.append(DocumentA(from: aData)
                
            }
            self.aList = aList
        }
    }
    
    private func loadB() {
        
        // Start listening
        Firestore.firestore().collection("colB").addsnapshotListener { (snapshot,error) in
            if let error = error {
                print("DEBUG: Unable to get user data: \(error.localizedDescription)")
                return
            }
            
            // Invalid data return
            guard let snapshot = snapshot else {
                print("DEBUG: null data returned")
                self.bList = nil
                return
            }
            
            // Update the info
            var bList: [DocumentB] = []
            snapshot.documents.forEach { document in
                let bdata = document.data()
                guard !bdata.isEmpty else {
                    return
                }
                bList.append(DocumentB(from: bdata))
                
            }
            self.userUnits = userUnits
        }
    }
}

当我调试时,我可以看到 aListbList 被发布了一次,但是,cList 一直被发布,最终吃掉了所有的内存......

cList 通过视图中的 onReceive 语句使用,该语句输出每个项目。

有人能告诉我为什么 combineLatest 继续发布 cList,尽管没有新的 aListbList 发布吗?

非常感谢。

queencce 回答:Swiftui + Firestore + CombineLatest 不断发布数据

很可能,您会遇到这样一种情况,您使用刚从 cList 接收到的值更新视图,这会导致重新计算 body,从而导致另一个 onReceive(vm.cList) {...},从而导致由计算属性 cList 返回的 发布者,它再次发出值并重复循环。

这是我的意思的简化示例:

class ViewModel: ObservableObject {
   @Published var aList: [Int] = [1,2]

   var cList: AnyPublisher<Int,Never> {
      $aList.map { $0 + $0 }.eraseToAnyPublisher()
   }
}

struct ContentView: View {
   @StateObject var vm = ViewModel()
   @State var list: [Int] = []

   var body: some View {
      VStack {
         ForEach(list,id: \.self) { v in
            Text("\(v)")
         }
      }
      .onReceive(vm.cList) { self.list = $0 }
   }
}

为避免这种情况,cList 不应是计算属性。它可能只是一个懒惰分配的常量:

lazy var cList: AnyPublisher<Int,Never> = 
   $alist.map { $0 + $0 }
         .eraseToAnyPublisher()
本文链接:https://www.f2er.com/712120.html

大家都在问