# 5 Combining Operators Written by Shai Mishali

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Now that the transforming and filtering operator categories are in your tool belt, you have a substantial amount of knowledge. You’ve learned how operators work, how they manipulate the upstream and how to use them to construct logical publisher chains from your data.

In this chapter, you’ll learn about one of the more complex, yet useful, categories of operators: Combining operators. This set of operators lets you combine events emitted by different publishers and create meaningful combinations of data in your Combine code.

Why is combining useful? Think about a form with multiple inputs from the user — a username, a password and a checkbox. You’ll need to combine this data to compose a single publisher with all of the information you need.

## Getting started

You can find the starter playground for this chapter in the projects/Starter.playground folder. Throughout this chapter, you’ll add code to your playground and run it to see how various operators create different combinations of publishers and their events.

## Prepending

You’ll start slowly here with a group of operators that are all about prepending values at the beginning of your publisher. In other words, you’ll use them to add values that emit before any values from your original publisher.

### prepend(Output…)

This variation of `prepend` takes a variadic list of values using the variadic `...` syntax. This means it can take any number of values, as long as they’re of the same `Output` type as the original publisher.

``````example(of: "prepend(Output...)") {
// 1
let publisher = [3, 4].publisher

// 2
publisher
.prepend(1, 2)
.store(in: &subscriptions)
}
``````
``````——— Example of: prepend(Output...) ———
1
2
3
4
``````
``````.prepend(1, 2)
``````
``````.prepend(-1, 0)
``````
``````——— Example of: prepend(Output...) ———
-1
0
1
2
3
4
``````

### prepend(Sequence)

This variation of `prepend` is similar to the previous one, with the difference that it takes any `Sequence`-conforming object as an input. For example, it could take an `Array` or a `Set`.

``````example(of: "prepend(Sequence)") {
// 1
let publisher = [5, 6, 7].publisher

// 2
publisher
.prepend([3, 4])
.prepend(Set(1...2))
.store(in: &subscriptions)
}
``````
``````——— Example of: prepend(Sequence) ———
1
2
3
4
5
6
7
``````
``````.prepend(Set(1...2))
``````
``````.prepend(stride(from: 6, to: 11, by: 2))
``````
``````——— Example of: prepend(Sequence) ———
6
8
10
1
2
3
4
5
6
7
``````

### prepend(Publisher)

The two previous operators prepended lists of values to an existing publisher. But what if you have two different publishers and you want to glue their values together? You can use `prepend(Publisher)` to add values emitted by a second publisher before the original publisher’s values.

``````example(of: "prepend(Publisher)") {
// 1
let publisher1 = [3, 4].publisher
let publisher2 = [1, 2].publisher

// 2
publisher1
.prepend(publisher2)
.store(in: &subscriptions)
}
``````
``````——— Example of: prepend(Publisher) ———
1
2
3
4
``````
``````example(of: "prepend(Publisher) #2") {
// 1
let publisher1 = [3, 4].publisher
let publisher2 = PassthroughSubject<Int, Never>()

// 2
publisher1
.prepend(publisher2)
.store(in: &subscriptions)

// 3
publisher2.send(1)
publisher2.send(2)
}
``````
``````——— Example of: prepend(Publisher) #2 ———
1
2
``````
``````publisher2.send(2)
``````
``````publisher2.send(completion: .finished)
``````
``````——— Example of: prepend(Publisher) #2 ———
1
2
3
4
``````

## Appending

This next set of operators deals with concatenating events emitted by publishers with other values. But in this case, you’ll deal with appending instead of prepending, using `append(Output...)`, `append(Sequence)` and `append(Publisher)`. These operators work similarly to their `prepend` counterparts.

### append(Output…)

`append(Output...)` works similarly to its `prepend` counterpart: It also takes a variadic list of type `Output` but then appends its items after the original publisher has completed with a `.finished` event.

``````example(of: "append(Output...)") {
// 1
let publisher = [1].publisher

// 2
publisher
.append(2, 3)
.append(4)
.store(in: &subscriptions)
}
``````
``````——— Example of: append(Output...) ———
1
2
3
4
``````
``````example(of: "append(Output...) #2") {
// 1
let publisher = PassthroughSubject<Int, Never>()

publisher
.append(3, 4)
.append(5)
.store(in: &subscriptions)

// 2
publisher.send(1)
publisher.send(2)
}
``````
``````——— Example of: append(Output...) #2 ———
1
2
``````
``````publisher.send(completion: .finished)
``````
``````——— Example of: append(Output...) #2 ———
1
2
3
4
5
``````

### append(Sequence)

This variation of `append` takes any `Sequence`-conforming object and appends its values after all values from the original publisher have emitted.

``````example(of: "append(Sequence)") {
// 1
let publisher = [1, 2, 3].publisher

publisher
.append([4, 5]) // 2
.append(Set([6, 7])) // 3
.append(stride(from: 8, to: 11, by: 2)) // 4
.store(in: &subscriptions)
}
``````
``````——— Example of: append(Sequence) ———
1
2
3
4
5
7
6
8
10
``````

### append(Publisher)

The last member of the `append` operators group is the variation that takes a `Publisher` and appends any values emitted by it to the end of the original publisher.

``````example(of: "append(Publisher)") {
// 1
let publisher1 = [1, 2].publisher
let publisher2 = [3, 4].publisher

// 2
publisher1
.append(publisher2)
.store(in: &subscriptions)
}
``````
``````——— Example of: append(Publisher) ———
1
2
3
4
``````

At this point, you know everything about appending and prepending values, sequences and even entire publishers.

### switchToLatest

Since this section includes some of the more complex combining operators in Combine, why not start with the most complex one of the bunch?!

``````example(of: "switchToLatest") {
// 1
let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<Int, Never>()
let publisher3 = PassthroughSubject<Int, Never>()

// 2
let publishers = PassthroughSubject<PassthroughSubject<Int, Never>, Never>()

// 3
publishers
.switchToLatest()
.sink(receiveCompletion: { _ in print("Completed!") },
.store(in: &subscriptions)

// 4
publishers.send(publisher1)
publisher1.send(1)
publisher1.send(2)

// 5
publishers.send(publisher2)
publisher1.send(3)
publisher2.send(4)
publisher2.send(5)

// 6
publishers.send(publisher3)
publisher2.send(6)
publisher3.send(7)
publisher3.send(8)
publisher3.send(9)

// 7
publisher3.send(completion: .finished)
publishers.send(completion: .finished)
}
``````
``````——— Example of: switchToLatest ———
1
2
4
5
7
8
9
Completed!
``````
``````example(of: "switchToLatest - Network Request") {
let url = URL(string: "https://source.unsplash.com/random")!

// 1
func getImage() -> AnyPublisher<UIImage?, Never> {
URLSession.shared
.map { data, _ in UIImage(data: data) }
.print("image")
.replaceError(with: nil)
.eraseToAnyPublisher()
}

// 2
let taps = PassthroughSubject<Void, Never>()

taps
.map { _ in getImage() } // 3
.switchToLatest() // 4
.store(in: &subscriptions)

// 5
taps.send()

taps.send()
}
taps.send()
}
}
``````
``````——— Example of: switchToLatest - Network Request ———
image: request unlimited
image: receive value: (Optional(<UIImage:0x600000364120 anonymous {1080, 720}>))
image: request unlimited
image: request unlimited
image: receive value: (Optional(<UIImage:0x600000378d80 anonymous {1080, 1620}>))
``````

### merge(with:)

Before you reach the end of this chapter, you’ll wrap up with three operators that focus on combining the emissions of different publishers. You’ll start with `merge(with:)`.

``````example(of: "merge(with:)") {
// 1
let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<Int, Never>()

// 2
publisher1
.merge(with: publisher2)
.sink(receiveCompletion: { _ in print("Completed") },
.store(in: &subscriptions)

// 3
publisher1.send(1)
publisher1.send(2)

publisher2.send(3)

publisher1.send(4)

publisher2.send(5)

// 4
publisher1.send(completion: .finished)
publisher2.send(completion: .finished)
}
``````
``````——— Example of: merge(with:) ———
1
2
3
4
5
Completed
``````

### combineLatest

`combineLatest` is another operator that lets you combine different publishers. It also lets you combine publishers of different value types, which can be extremely useful. However, instead of interleaving the emissions of all publishers, it emits a tuple with the latest values of all publishers whenever any of them emit a value.

``````example(of: "combineLatest") {
// 1
let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<String, Never>()

// 2
publisher1
.combineLatest(publisher2)
.sink(receiveCompletion: { _ in print("Completed") },
receiveValue: { print("P1: \(\$0), P2: \(\$1)") })
.store(in: &subscriptions)

// 3
publisher1.send(1)
publisher1.send(2)

publisher2.send("a")
publisher2.send("b")

publisher1.send(3)

publisher2.send("c")

// 4
publisher1.send(completion: .finished)
publisher2.send(completion: .finished)
}
``````
``````——— Example of: combineLatest ———
P1: 2, P2: a
P1: 2, P2: b
P1: 3, P2: b
P1: 3, P2: c
Completed
``````

### zip

You’ll finish with one final operator for this chapter: `zip`. You might recognize this one from the Swift standard library method with the same name on `Sequence` types.

``````example(of: "zip") {
// 1
let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<String, Never>()

// 2
publisher1
.zip(publisher2)
.sink(receiveCompletion: { _ in print("Completed") },
receiveValue: { print("P1: \(\$0), P2: \(\$1)") })
.store(in: &subscriptions)

// 3
publisher1.send(1)
publisher1.send(2)
publisher2.send("a")
publisher2.send("b")
publisher1.send(3)
publisher2.send("c")
publisher2.send("d")

// 4
publisher1.send(completion: .finished)
publisher2.send(completion: .finished)
}
``````
``````——— Example of: zip ———
P1: 1, P2: a
P1: 2, P2: b
P1: 3, P2: c
Completed
``````

## Key points

In this chapter, you learned how to take different publishers and create meaningful combinations with them. More specifically, you learned that:

## Where to go from here?

This has been quite a long chapter, but it includes some of the most useful and involved operators Combine has to offer. Kudos to you for making it this far!

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below: