Saying hello to Combine framework — Part-1

Shail Patel
Mindful Engineering
7 min readDec 7, 2019
Photo by Steve Johnson on Unsplash

This year in WWDC Apple introduced a lot of new stuff to the developer world. There were many new things like SwiftUI, Dark Mode and Catalyst, But the most interesting thing Apple introduced was the Reactive framework, called Combine. This post is not for FRP(Functional Reactive Programming), so we can directly start with the Combine framework. In this post, we will introduce you to Combine with one basic example.

In Apple’s words, Combine is:

A declarative Swift API for processing values over time.

When to use Combine

Combine is useful when you want immediate effect of an action. User interfaces fit very naturally into this pattern.

The classic example in functional reactive programming and user interfaces frequently shown form validation, where user events such as changing text fields, taps or mouse-clicks on UI elements make up the data being streamed. Combine takes this quite a bit further, enabling watching properties, binding to objects, sending and receiving higher level events from UI controls, and supporting integration with almost all of Apple’s existing API ecosystem.

Core Concepts

Publisher

Publisher is basically a provider of data, when it is available and requested. A publisher that hasn’t had any request yet will not provide any data. The basic block for publisher is as follows:

From the above code snippet you can see that Publisher has two associated types Output and Failure. Output describes the data which is requested by the subscriber. And the failure defines any failure related to that data.

Subscriber

Another core concept of Combine is Subscriber. Subscriber is responsible for requesting data, accepting data and handling possible failures provided by a publisher. In combine the subscriber initiates the request for data, and controls the amount of data it receives. The basic block of subscriber is as follows:

From above block you can see that subscriber has two associated types Input and Failure. Input describes the type of data which is requested to Publisher. Failure defines the failure.

When you connect a subscriber to a publisher, both types must match: Output to Input and Failure to Failure.

Operators

Operator is an object that acts like both a subscriber and a publisher. Operators are classes that adopt the Subscriber protocol and Publisher protocol. They support subscribing to a publisher, and sending results to any subscriber. Operators can be used to transform both the types Output and Failure. To choose the perfect operator for your use is very essential otherwise it will give you an error.

Subjects

A subject is a publisher that you can use to “inject” values into stream, by calling its send(_:) method. This can be useful for adapting existing imperative code to the combine model.

Lifecycle of Publishers and Subscribers

  1. When the subscriber is attached to a publisher, it starts with a call to subscriber(subscriber).
  2. The publisher in turn acknowledges the subscriber calling receive(subscription).
  3. After the subscription has been acknowledged, the subscriber requests N (or fewer) values with request(_ : Demand).
  4. The publisher may then (as it has values) sends N (or fewer) values: receive(_ : Input). A publisher should never send more than the demand requested.
  5. Also after the subscription has been acknowledged, the subscriber can send a cancellation with cancel()
  6. A publisher may optionally send completion: receive(completion:). A completion can be either a normal termination, or may be a .failure completion, optionally propagating an error type.

Ok enough of theory, let’s start with some coding part!

Example

Here we are creating the form view in which there are three text fields like username, password and confirm password. There are two labels for validation of username and password. There is one button for submit which enabling and disabling of validating all the fields and it will change its color.

In this demo we are using the MVVM pattern. If you are not familiar with the MVVM pattern I suggest you to first check the MVVM pattern.

First of all, create one ViewController as FormVC and ViewModel for that ViewController named as FormViewModel. Now we are good to go, Let’s start our first combine project. It is important to import Combine before we start coding using Combine.

First create two subscribers in FormVC as shown below using AnyCancellable.

usernameSubscriber and passwordSubscriber are used to subscribe to the changes happening in respective textfields.

Now we will create validations in FormViewModel. First we are going to create three published property for username, password and confirm password like below.

Initially, all the fields are blank because we didn’t enter anything in that text fields. Published allows you to wrap a property and enabling you to get a publisher that triggers data updates whenever the property is changed.

Now we will create two publishers for publishing the username validation message and password validation message.

There are two types for creating the publisher using subject. The first one is PassthroughSubject and another is CurrentValueSubject. Use CurrentValueSubject to publish whenever you update the subject’s underlying value. And use PassthroughSubject to publish values on-demand by calling its send(_:) method.

Now let’s add the validation messages on the username textfield.

What we just did?

  1. Here we are using AnyPublisher<String?, Never> means the output is optional String and the failure type is Never.
  2. Here we used $ before username because we want the change to appear whenever the value is changed.
  3. We are using map operator to do some operation according to output.
  4. First we are checking for empty username validation.
  5. If username is not empty then it must have at least 3 characters.
  6. We are using send(_:) method on publisher to send the output to subscriber.
  7. And in the last we are using eraseToAnyPublisher(). that will do type erasure on the chain of operators so the resulting signature is of type AnyPublisher<String?, Never>.

Now let’s add the validation message on the password and confirm password textfield.

Here is what we just did:

  1. Here we are using AnyPublisher<String?, Never> means the output is optional string and the failure type is Never.
  2. Here we used CombineLatest for combining the latest element from password and confirmPassword publishers.
  3. Here we used $ before password and confirmPassword because we want the change to be notified whenever the value is changed.
  4. Here we use receive(on: RunLoop.main) because we want to do the operation in main thread.
  5. We are using map operator to do some operation according to output.
  6. We are checking if both password and confirmPassword matched or not and if matches it must have length of 5 characters.
  7. Then we send the output using send(_:) method.
  8. Finally we use eraseToAnyPublisher() for output type assurance.

Now if both username and password validation passes then we have to enable submit button and want to do ready form for submission.

What we just did?

  1. Here we are using AnyPublisher<(String?, String?)>, Never> because we want to pass the username and password on the submit button so there are two option String for Output and Failure type is Never.
  2. Here we used CombineLatest for combining the latest element from validateUserName and validatePassword publishers.
  3. Finally we use eraseToAnyPublisher() for output type assurance.

We completed validations. That’s it for View Model now let’s go to view controller.

First create instance of FormViewModel.

Now let’s bind the Published variable from FormViewModel to our textfields.

What we just did?

  1. Here I am using textfield’s EditingChanged method(@IBAction) for getting changes in textField, you can also use delegate methods as well.
  2. After that we give the value of textfield’s text to FormViewModel published var so when the value of textfield change that publisher will be called.

Now let’s create one method in which we can check for validation messages and display in label, as well do submit button enable and disable functionality. We have to call that method in viewDidLoad() .

What we just did?

  1. First we are doing some operation on userNameMessagePublisher from ViewModel and show the message from that publishers output to username validation label.
  2. We used “sink” subscriber for displaying the message in label.
  3. In next step, we give that subscriber to usernameSubscriber which we have created in starting.
  4. Same thing we did with passwordMessagePublisher and give it to passwordSubscriber.
  5. Now using readyToSubmit Publisher of FormViewModel we are doing operation for submit button enabling and disabling as-well color changing of that button.
  6. We are using map operator which returns nil if any value is nil. Checking against a nil value provides the boolean used to enable or disable the submit button.
  7. Using sink subscriber we are receive boolean value and using that value we can change the color of button as-well change the state of button enable or disable.
  8. The store method is available on the Cancellable protocol, which is explicitly set up to support saving off references that can be used to cancel a request.

Conclusion

In this first part of Combine framework I’ve demonstrated how you can use Combine for validation using MVVM. The best thing about Combine is the deep integration with Swift Foundation. In the next part we will discuss about Publisher, Subscriber, Operators and Subjects in more details, and we will discuss some new points like integration with SwiftUI, Built-in publishers and subscribers and how we can use combine for API calling. There are much more to understand about Combine and we will cover all in this series of Combine framework.

You can find the second part of this series Saying hello to Combine framework (API Call & Parsing) — Part-2 .

You can download the full source code from following GitHub Project.

Here is the second part of this series Saying hello to Combine framework (API Call & Parsing) — Part-2.

Stay tuned with Mindful Engineering, we will be posting more detailed posts regarding Combine and such other interesting stuff in upcoming weeks.

--

--