Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine Publishers.Merge but with Publishers.combineLatest behaviour

Tags:

swift

combine

I am currently trying to implement the merging of two publishers. But I can't find a solution for my use case.

I want to merge 2 publishers that both emit an array of structs of the same type. I want the combined publisher to emit values when either one of the merged publishers emit a new value.

Basically this would be a use case for Publishers.CombineLatest, but since my underlying publishers both emit values of the same type a merge would be more fitting here. But Publishers.Merge will not remember the last values of the merged publishers.

Therefore I would like to have a Publishers.CombineLatest behaviour with a Publishers.Merge operation. Is there something inside the Combine framework which can accomplish this kind of behaviour ?

Rough example what should happen:

Definitions:

PublisherA: emits -> [Value]
PublisherB emits -> [Value]

CombinedAB: -> [Value]


PublisherA changes: CombinedAB -> [NewA, OldB]
PublisherB changes: CombinedAB -> [OldA, NewB]

let a = CurrentValueSubject<[Int], Never>(["a", "b", "c"])
let b = CurrentValueSubject<[Int], Never>(["d", "e", "f"])

let combined = Publisher.AnyThing(a, b)

combined.sink {
   print($0)
}


b.send(["g", "h", "i"])


Outputs:
["a", "b", "c", "d", "e", "f"]
["a", "b", "c", "g", "h", "i"]

So it's basically a Publishers.CombineLatest but without emitting a tuple of (NewA,OldB) but instead already merged, because both values have the same type.

Any help is much appreciated.

like image 549
grahan Avatar asked Feb 10 '20 11:02

grahan


People also ask

What is a publisher combine?

Within the world of Combine, an object that emits such asynchronous values and events is called a publisher, and although the framework does ship with quite a large number of built-in publisher implementations, sometimes we might want to build our own, custom ones in order to handle specific situations.

What is sink in combine?

What's a sink? While a complete explanation of Combine, publishers, subscribers, and sinks is beyond the scope of this article, for our purposes here it's probably enough to know that in Combine a sink is the code receives data and completion events or errors from a publisher and deals with them.

What is Combinelatest Swift?

Subscribes to an additional publisher and publishes a tuple upon receiving output from either publisher.


1 Answers

Assuming that your combine operation is just concat of the subarrays you can do:

let a = CurrentValueSubject<[String], Never>(["a", "b", "c"])
let b = CurrentValueSubject<[String], Never>(["d", "e", "f"])

let combined = Publishers.CombineLatest(a, b).map(+)

combined.sink {
   print($0)     //["a", "b", "c", "d", "e", "f"] and ["a", "b", "c", "g", "h", "i"]
}


b.send(["g", "h", "i"])

I am not completely sure what you mean with "already merged". If you want to have the latest emitted array always at the end of the combined array then you might need a scan operator before the map(+) to be able to compare with previous emissions and swap them.

like image 160
Fabio Felici Avatar answered Sep 29 '22 00:09

Fabio Felici