CurrentValueSubject send(value) 不会触发 receiveValue

CurrentValueSubject send(value) doesn't trigger receiveValue

我有一个 CurrentValueSubject 来保存从 Firebase 获取请求接收到的数据。

final class CardRepository: ObservableObject {

    private let store = Firestore.firestore()
    var resultSubject = CurrentValueSubject<[Card], Error>([])
    init() {
    }
    
    func get() {
        store.collection(StorageCollection.EnglishCard.getPath)
            .addSnapshotListener { [unowned self] snapshot, err in
                if let err = err {
                    resultSubject.send(completion: .failure(err))
                }
                if let snapshot = snapshot {
                    let cards = snapshot.documents.compactMap {
                        try? [=10=].data(as: Card.self)
                    }
                    resultSubject.send(cards)
                }
            }
    }
}

在我的 ViewModel 中,我希望每当 resultSubject 发送或 emits 一个 value。它将更改 state 并将 value 附加到 succes 状态。

class CardViewModel: CardViewModelProtocol, ObservableObject {
    
    @Published var repository: CardRepository
    @Published private(set) var state: CardViewModelState = .loading
    private var cancellables: Set<AnyCancellable> = []

    required init (_ repository: CardRepository) {
        self.repository = repository
        bindingCards()
        
    }
    
    private func bindingCards() {
        let _ = repository.resultSubject
            .sink { [unowned self] comp in
                switch comp {
                case .failure(let err):
                    self.state = .failed(err: err)
                case .finished:
                    print("finised")
                }
            } receiveValue: { [unowned self] res in
                self.state = .success(cards: res)
            }

    }
    
    func add(_ card: Card) {
        repository.add(card)
    }
    
    func get() {
        repository.get()
    }

}

在我的 ContentView 上,它将显示 print result

的按钮
struct ContentView: View {
    @StateObject var viewModel = CardViewModel(CardRepository())
    var body: some View {
        Group {
            switch viewModel.state {
            case .loading:
                ProgressView()
                Text("Loading")
            case .success(cards: let cards):
                let data = cards
                Button {
                    print(data)
                } label: {
                    Text("Tap to show cards")
                }
            case .failed(err: let err):
                Button {
                    print(err)
                } label: {
                    Text("Retry")
                }
            }
            Button {
                viewModel.get()
            } label: {
                Text("Retry")
            }
        }.onAppear {viewModel.get() }
    }
}

我的问题是下面的块在我第一次将它绑定到 resultSubject 时只触发一次。

} receiveValue: { [unowned self] res in
                self.state = .success(cards: res)
            }

我确实添加了调试,resultSubject.send(cards) 每次都能正常工作。

您需要将从 .sink 返回的 Cancellable 存储在 class 中,这样它就不会被释放:

如果您想使用多个 Publishers,则在一组 var cancellables = Set<AnyCancellable>() 中,或者在 var cancellable: AnyCancellable?.

像这样添加.store(in &cancellables)

} receiveValue: { [unowned self] res in
    self.state = .success(cards: res)
}.store(in: &cancellables)

编辑:

ObservableObject classes 我们不使用 sink,我们 assign@Published:

let _ = repository.resultSubject
    .assign(to: &$self.state)