Reactive Programming in iOS with Combine

Feb 4 2021 · Swift 5.3, macOS 11.0, Xcode 12.2

Part 3: Combining Operators

15. Prepend

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 14. Introduction Next episode: 16. Append

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 15. Prepend

With transforming and filtering operators in your toolbelt, it’s time to move onto a complex, but useful, category of operators - Combining Operators. These operators let you combine events emitted by different publishers to create combinations of data to send to consumers.

A great example of this is performing authentication in your app - you’ll need to get a username, password and checkbox value (to remember the username) from the user, combine them, and send them downstream. Let’s start with the family of Prepending operators - we’ll go over each type, and then demo them in a playground.

The first prepend operator we’ll look at is a version that takes a variadic list of values denoted by the variadic syntax, which is 3 periods in a row. This means it can take any number of values, as long as they are of the same type as the original publisher. Look at the marble diagram. The original publisher only emits 3 and 4. With the prepend operator you can prepend the values 1 and 2, sending 1, 2, 3, and 4 to the consumer.

A variation of prepend takes in a Sequence-conforming object instead of a variadic set of values. This marble diagram shows the example passing in an array of values instead of the variadic collection, but the result is the same - 1, 2, 3, and 4 get sent to the consumer. Keep in mind that not all Sequence-conforming objects are equal with respect to ordering - Sets are unordered, while arrays are ordered.

Another variation of prepend prepends the values emitted by a second publisher before the values of the original publisher. Here the marble diagram show the original publisher emitting 3 and 4, and a second publisher emitting 1 and 2. As before, the final sequence is 1, 2, 3 and 4. Let’s look at all of these in a demo.

Make an instance of the example(of:) method to examine the behavior of the prepend(Output) operator. Make an initial publisher from an array that contains 3 and 4. Connect a sink subscriber to the publisher, and also call the store method to store the subscriptions in a collection for bulk cancellation when the collection is deinitialized.

Add a prepend operator between the publisher and sink subscriber, and use the values 1 and 2 as the arguments. Executing the example code shows that the values get prepended and 1, 2, 3, and 4 are emitted. Also, since operators can chain, add another operator to prepend -1 and 0 in front of that.

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

  // 2
  publisher
    .prepend(1, 2)
    //.prepend(-1, 0)
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)
}

Make another example(of:) stub to explore prepend(Sequence) with 5, 6, and 7 in the initial array. This time, instead of a variadic list, add a prepend operator with an array containing 3 and 4, and following that add a Set containing the range from 1 to 2. Executing this exaxmple causes the sink to receieve and print out 1 though 7.

Finally, add a prepend with a stride that generates every other value from 6 through 11, since Stridable conforms to Sequence. This will prepend 6, 8, and 10 to the string generated by the sink subscriber.

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

  // 2
  publisher
    .prepend([3, 4])
    .prepend(Set(1...2))
    //.prepend(stride(from: 6, to: 11, by: 2))
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)
}

The prepend(Publisher) operator is fairly straight forward. Make another example(of:) stub, this time with 2 publishers - one with an array with 3 and 4 in it, and another with 1 and 2 in it. Insert the prepend operator between publisher 1 and the sink. publisher2 will emit values before publisher1 emits its values, again resulting in the 1, 2, 3, and 4 sequence.

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

  // 2
  publisher1
    .prepend(publisher2)
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)
}

Remember though that for this sort of operator to work, the Publisher has to send a completion event so the original publisher’s values can be emitted. Change the above example so that publisher2 is a PassthroughSubject publisher, allowing you to send one value at a time. Send values 1 and 2 through publisher2, and run the playground.

You’ll see that nothing else ever gets emitted. This is because there has been no indication that publisher 2 is done. To fix this, send a completion event through publisher2 and rerun the playground. Now you see 1, 2, 3, and 4 all make their way to the sink for output to the console.

example(of: "prepend(Publisher) #2") {
  // 1
  let publisher1 = [3, 4].publisher
  let publisher2 = PassthroughSubject<Int, Never>()

  // 2
  publisher1
    .prepend(publisher2)
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)

  // 3
  publisher2.send(1)
  publisher2.send(2)
  //publisher2.send(completion: .finished)
}

In this episode you learned prepending operators, which add emissions from one publisher before the original publisher. The prepend(Output) operator takes a variadic list of values, as long as they are the same type as the original publisher. The prepend(Sequence) operator takes any collection that conforms to the Sequence protocol. Don’t forget that some sequences are ordered and some aren’t!

Finally, the prepend(Publisher) operator emits the values from the passed in publisher before emitting the values from the original publisher. The passed in publisher must send a completion event so the operator knows when to emit values from the original publisher.

In the next episode we’ll look at a close relative of the prepend family of operators - the append family.