0

我正在尝试合并来自两个不同集合的查询的两个已发布对象,以使用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不断发布的内容最终会吃掉所有的内存......

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

谁能告诉我为什么combineLatest不断出版cList,虽然没有新鲜aListbList出版?

提前谢谢了。

4

1 回答 1

0

很有可能,您会使用刚刚从 接收到的值更新视图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()
于 2021-03-22T22:36:57.733 回答