It will take about 10 minutes to finish reading this article.
Overview
Continuing from the previous article, we will continue to introduce some common types in the Combine framework.
11. AnySubscriber
Subscriber type erasure (Type Erasure) version. Used to encapsulate subscribers and allow you to erase the specific type of Subscriber, thereby increasing the flexibility of the code. Normally, you don’t need to create an AnySubscriber object directly as it is usually used inside the Combine operator and the framework.
An AnySubscriber object can be created by passing a specific subscriber to AnySubscriber’s initialization method. This will encapsulate the original subscriber and do type erasure.
1 |
|
AnySubscriber can be used to subscribe to Publisher like a normal subscriber, thereby receiving values and completion status in the data stream. You can pass AnySubscriber to operators such as sink and assign.
12. Subject
Subject is a special kind of Publisher and Subscriber. It can be used to create and manage data flows, allowing you to post values manually or send external values into the data flow. Subject acts as a relay for data in Combine, allowing you to add, update, and distribute values in the data flow. It has 2 main types of Subject, each type has a different purpose.
1. PassthroughSubject:
PassthroughSubject is the most common Subject type, which passes the received value directly to its subscribers. It does not cache or replay values, it only delivers the current value to the subscriber.
1 | //Create PassthroughSubject, specify input and error type |
2. CurrentValueSubject:
CurrentValueSubject is similar to PassthroughSubject, but it has an initial value and sends the current value to new subscribers when subscribing. It can be used to represent an observable object with current state.
1 | import Combine |
The result is:
1 | Received value: 0 |
*** Note: ***
The @Published property wrapper is actually a property wrapper based on CurrentValueSubject, which enables changes to properties to be automatically published to subscribers.
13. Scheduler
Scheduler is a protocol that defines when and how to execute a closure. It is a very important concept that is used to manage and control the execution of events in time. Scheduler is an abstract type used for scheduling tasks (usually asynchronous tasks), which defines when the task should be executed and on which thread or queue it should be executed. In Combine, Scheduler is usually used for operations such as operators, delays, timers, and subscriptions to ensure the order and timing of events.
1 | protocol Scheduler<SchedulerTimeType> |
Sample code:
1 | import Combine |
Combine provides multiple types related to the Scheduler type, each type has different behaviors and uses. Here are some commonly used types:
1. ImmediateScheduler
A Scheduler type. Not introducing any latency or asynchronicity, it executes the task immediately on the current thread. This is useful for performing synchronous tasks or simulating immediate execution when testing.
1 | import Combine |
2. SchedulerTimeIntervalConvertible
SchedulerTimeIntervalConvertible is a protocol. It defines a type that converts time intervals (time units) into specific time units for use in the Combine scheduler.
In Combine, time units are usually expressed as seconds (TimeInterval), but different schedulers may use different time units, such as milliseconds or microseconds. Therefore, SchedulerTimeIntervalConvertible provides a general method for converting time units to those appropriate for a specific scheduler.
The protocol defines the following methods:
1 | protocol SchedulerTimeIntervalConvertible { |
These methods allow you to convert time units (seconds, milliseconds, microseconds, nanoseconds) to time units suitable for the scheduler and create a type that implements the SchedulerTimeIntervalConvertible protocol. This is typically used in the context of a custom scheduler to ensure time unit consistency.
Here is an example that demonstrates how to use the SchedulerTimeIntervalConvertible protocol to create a custom time unit type:
1 | import Combine |
14. ObservableObject
ObservableObject is a protocol in the SwiftUI framework built on Combine. It is used to create observable objects and is usually used to build responsive interfaces. It is one of the core concepts of data-driven interfaces in SwiftUI.
1 | import SwiftUI |
In the above example, we have created a MyViewModel class that follows the ObservableObject protocol and marked two observable properties using the @Published property wrapper. Then, in the view ContentView, we use the @ObservedObject property wrapper to bind the viewModel to the view, making it an observable object. When properties in the viewModel are modified on button click, the view automatically updates to reflect the changes.
15. AsyncPublisher/AsyncThrowingPublisher
AsyncPublisher/AsyncThrowingPublisher It is a Publisher that exposes its elements in the form of (throwing) asynchronous sequences. It is defined as follows:
1 | struct AsyncPublisher<P> where P : Publisher, P.Failure == Never |
The sample code is as follows:
1 | import Combine |
16. CustomCombineIdentifierConvertible
It is a protocol in the Combine framework that is used to help uniquely identify publisher chains. This protocol is typically used when creating custom Subscriber or Subscription types so that development tools can uniquely identify these publisher chains within your application.
If you create a custom subscription or subscriber type, you need to implement this protocol so that development tools can uniquely identify the publisher chain in your application. If your type is a class, Combine provides you with an implementation of combineIdentifier. If your type is a struct, set the identifier as follows:
1 | let combineIdentifier = CombineIdentifier() |
Where CombineIdentifier is the unique identifier used to identify the publisher’s information flow. Let’s look at a sample code:
1 | import Combine |
17. The Protocol of Subscription
Subscription is a protocol that represents the subscription relationship between Subscriber and Publisher. Specifically, Subscription describes how to manage subscriptions, including operations such as canceling subscriptions and requesting elements.
1 | public protocol Subscription: Cancellable, CustomCombineIdentifierConvertible { |
request(:) method: By calling the request(:) method, a subscriber can request to receive elements from the publisher. The request(_:) method accepts a parameter demand, which is a Subscribers.Demand enumeration value, indicating how many elements the subscriber wants to receive from the publisher. Publishers should send elements based on subscriber demand.
The Subscription protocol is a very important part of Combine. It is responsible for managing the life cycle of subscriptions and the delivery of elements. Subscribers can use the request(_:) method to control the rate at which elements are received, while the cancel() method is used to cancel a subscription when it is no longer needed.
In Combine, there is usually no need to manually implement the Subscription protocol because Combine provides many built-in operators and types to handle subscriptions. However, if you need to create a custom subscription, you may need to implement the Subscription protocol to define the behavior of the subscription.
Below is a simple sample code that demonstrates how to create a custom subscription that conforms to the Subscription protocol and use it to manage the subscription’s lifecycle and request elements.
1 | import Combine |