簡體   English   中英

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? $0.data(as: Card.self)
                    }
                    resultSubject.send(cards)
                }
            }
    }
}

在我的 ViewModel 中,我希望每當resultSubject發送或emits一個value時。 它將更改state並將該value附加到succes state。

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 var cancellables = Set<AnyCancellable>()中,或者在var cancellable: AnyCancellable? .

像這樣添加.store(in &cancellables)

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

編輯:

ObservableObject類中我們不使用sink ,我們assign給一個@Published

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM