Zorayr
Zorayr

Reputation: 24884

combineLatest on CurrentValueSubject doesn't emit when combining with @Published property

I am using Combine with Swift5; I have a CurrentValueSubject that I am combining with a @Published dictionary variable.

The problem is that when the current value is updated, map never gets called! This is specifically an issue with @Published variable since it works with other streams that are not using @Published.

@Published var userModels: [String: UserModel] = [:]
var chatModels: CurrentValueSubject<[ChatModelFirebase], Never> = CurrentValueSubject([])

chatModels
    .combineLatest(userModels.publisher)
    .map({ (chatModels, userModels) -> [ChatViewModel] in
        print("Hello") // Never gets called! 😢
        return []
        })
.assign(to: \.chatViewModels, on: self)
.store(in: &cancellableSet)


// Update chat model's value, and notice that map never gets called!
chatModels.values = []

There are no errors, code compiles and runs, but I never get the results of stream updates. The problem will be fixed if I update userModels to also be CurrentValueSubject, but the question is why is combineLatest(..) breaking with @Published?

Upvotes: 0

Views: 1567

Answers (1)

New Dev
New Dev

Reputation: 49590

I think you're confusing between two publishers: the Published<Value>.Publisher publisher created from a @Published property via $userModels and the Publishers.Sequence publisher that you get from userModels.publisher.


The Published one publishes the value on every change. So, $userModels would publish the the [:] value right away, and then again with every change:

class Foo {
  @Published var dict: [String: Int] = [:]
}
let foo = Foo()

foo.$dict
   .sink { print($0) }

foo.dict = ["one": 1, "two": 2]

the output is:

[:]
["one": 1, "two": 2]

The Sequence publisher publishes each value from a sequence, which for a dictionary is a series of tuples of (key, value). For an empty sequence, it publishes no values:

var dict: [String: Int] = [:]

dict.publisher
  .sink { print($0) } // will not print anything

In your case, you're using .combineLatest with a Sequence publisher from an empty dictionary, which publishes no values, and so CombineLatest publishes no values.

What you might have be looking for was to subscribe to a Published publisher of userModels property:

chatModels.combineLatest($userModels)
   .sink { print($0) }   

the initial output then would immediately be:

([:], [])

Upvotes: 1

Related Questions