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)
我有一个 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)