Requirements: Link to heading
To understand this tutorial we need knowledge about:
- Delegation Pattern
- Combine: Swift 5, iOS13, WWDC 2019
- Closures: Swift 2.0, WWDC 2015
1) Use Case: Communicating viewcontrollers (viewcontroller with cell/view) Link to heading
One of the most common ways to communicate a viewcontroller with a cell or views is through the delegate pattern with protocols or closures. For example, if we want to know if a click was made on the cell or view and the viewcontroller wants to know this event to trigger some action, the delegate pattern will be implemented through protocols.

The problem with this approach is that it generates high coupling since if a change is made to the protocol (for example, adding a new method or changing a parameter), all view controllers should be modified when the protocol is changed.

A solution to lower coupling is through the use of the Combine framework that allows us to avoid protocols.
Our example use case shows us that when the button in selfview is tapped, the viewcontroller can trigger some action.
For this use case we use a Publisher called PassthroughSubject which notifies the viewcontroller when a specific action is performed on the cell. Then, the viewcontroller subscribes to this Publisher with the subscribeToCellActions method to listen for events from each cell individually via the following code:

2) Use Case: Network Layer Link to heading
Commonly, libraries such as PromiseKit, Alamofire and Moya are used at the network layer to manage the asynchronous call to the APIs, error handling and other stuff. Currently we can use Combine or async/await (we will see it in another post) for native and asynchronous handling, with api calls, decoding and error handling as shown in the following code:

As we observe, Combine has already defined operators such as ‘.map’ and ‘.decode’ to decode the api response in our model.

In the code above is used:
-
receiveCompletion: This is the first parameter of the sink method. It receives a completion closure that is executed when the value is published, either with success or with an error.
-
receiveValue: This is the second parameter of the sink method. It receives a closure that is executed every time the publisher emits a new value. In this case, when the publisher of fetchTodos() emits new values, this closure is executed. This is where we can change the background thread to the main one to update some UI elements.
-
.store(in: &cancellables): This is how Combine stores the publisher subscription in a set of cancelables. By adding it to the cancellable set, you ensure that the subscription stays alive for as long as you need it to, usually as long as the object containing it is also alive (viewcontroller). When the object containing the cancellables set is freed from memory, all subscriptions stored in the set are also automatically canceled, preventing memory problems such as memory leaks.