What Is Combine In Swift?

Introduction

 
The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers. 
 
Combine can be used to simplify your code with things like delegates, notifications, timers, completion blocks, and callBacks, before the Combine framework, there have been third-party reactive frameworks (RXSwift) available for some time on iOS, but now Apple has made its own.
 
Combine has some core concepts that need to be understood:
  • Publishers and Subscriber
  • Operators
  • Subjects 

Publishers

 
The Publisher protocol declares a type that can deliver a sequence of values over time. Publishers have operators to act on the values received from upstream publishers and republish them.
 
Publisher has two associated types, the first one is Output, which is the kind of value reproduced by a publisher. The second one is Failure, which is a kind of error produced by the publisher.
 
The publisher has one key function called subscribe. This function needs subscriber input as a parameter to match with publisher's output. 
 
Combine provides a number of additional convenience publisher:
  • Just
  • Future
  • Deferred
  • Empty
  • Sequence
  • Fail
  • Record
  • Share
  • Multicast
  • ObservableObject
  • Published
There are some Apple API outside of Combine framework that provide Publishers as well:
 

SwiftUI

 
SwiftUI uses the @Published and @ObservedObject property wrappers, provides by a combine, to implicitly creates a publisher and support its declarative view mechanisms.
 
Example
  1. //Published  
  2.   
  3. class DelayedUpdater: ObservableObject {  
  4.     @Published var value = 0  
  5.   
  6.     init() {  
  7.         for i in 1...10 {  
  8.             DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {  
  9.                 self.value += 1  
  10.             }  
  11.         }  
  12.     }  
  13. }  
  14.   
  15. //ObservedObject  
  16.   
  17. struct ContentView: View {  
  18.     @ObservedObject var updater = DelayedUpdater()  
  19.   
  20.     var body: some View {  
  21.         Text("Value is: \(updater.value)")  
  22.     }  
  23. }  

Foundation

  • URLSession.dataTaskPublisher
  • .publisher on KVO instance
  • NotificationCenter
  • Timer
  • Result 

Subscriber

 
A Subscriber instance receives a stream of elements from a Publisher, along with life cycle events describing changes to their relationship. A given subscriber's Input and Failure associated types must match the Output and Failure of its corresponding publisher.
 
A Subscriber is responsible for requesting data and accepting the data (and possible failures) provided by a publisher. This receives values and completion and is of reference types, which mean classes.
 
Example
  1. protocol Subcriber {  
  2.     associatedtype Input  
  3.     associatedtype Failure: Error  
  4.     func receive(subscription: Subscription)  
  5.     func receive(_ intput:Input) -> Subscribers.Demand  
  6.     func receive(completion:Subscribers.Completion<Failure>)  
  7. }  
A subscriber is described with two associated types, one for Input and one for Failure. The subscriber initiates the request for data and controls the amount of data it receives.
 
Publishers and operators are pointless unless something is listening to the published events. That something is the Subscriber. 
Combine provides the following subscribers as operators on the Publisher type,
  • sink(receiveCompletion:receiveValue:) executes arbitrary closures when it receives a completion signal, and each time it receives a new element.
  • assign(to:on:) writes each newly-received value to a property identified by a key path on a given instance. 
Subscribers can support cancellation, which terminates a subscription and shuts down all the stream processing prior to any Completion sent by the publisher. Both Assign and Sink conform to the cancellable protocol.
 

Sink

 
This concept a closure that receives any resulting values from the publisher. This allows the developer to terminate a pipeline with its own code. This subscriber is also extremely helpful when writing unit tests to validate either publishers or pipelines.
 
Example
  1. import Combine  
  2.   
  3. let _ = Just("Hello, Pravesh Dubey")  
  4.     .map { (value) -> String in  
  5.         return value  
  6. }  
  7. .sink { (receivedValue) in  
  8.     print(receivedValue)  
  9. }  
  10. Output: Hello, Pravesh Dubey
Just keyword is a publisher that will only publish the output and failure type would be never.
 
Sink
 
This method creates the subscriber and immediately requests an unlimited number of values that will get the returned value from the publisher.
 

Assign

 
Assign is passed down from the publisher to an object defined by a keypath. The keypath is set when the pipeline is created.
 
If assign is being used to update a user interface element, you need to make sure that it is being updated on the main thread. This call makes sure that the subscriber is received on the main thread.
 
Thanks for Reading!!!