ImmediatePublisher
is the protocol for publishers that publish a value or fail, right on subscription.
/// x-------> can fail immediately.
/// o - - - > can publish one value immediately (and then publish any number
/// of values, at any time, until the eventual completion).
protocol ImmediatePublisher: Publisher { }
When you import CombineTraits, many Combine publishers are extended with conformance to ImmediatePublisher
, such as Just
and Fail
. Other publishers are conditionally extended, such as Publishers.Map
or Publishers.FlatMap
.
Conversely, some publishers such as Publishers.Sequence
are not extended with ImmediatePublisher
, because not all sequences contain at least one element. And Future
or URLSession.DataTaskPublisher
are not immediate publishers, because they are asynchronous.
- AnyImmediatePublisher: a replacement for
AnyPublisher
- Building Immediate Publishers
AnyImmediatePublisher
is a publisher type that hides details you don’t want to expose across API boundaries. For example, the user of the publisher below knows that it certainly publishes one String
right on subscription:
/// 👍 Publishes one name right on subscription, and then any number of names.
func namePublisher() -> AnyImmediatePublisher<String, Never>
Compare with the regular AnyPublisher
, where documentation is the only way to express the "immediate" guarantee:
/// 😥 Trust us: this publisher publishes one name right on subscription.
func namePublisher() -> AnyPublisher<String, Never>
You build an AnyImmediatePublisher
with the ImmediatePublisher.eraseToAnyImmediatePublisher()
method. For example:
func namePublisher() -> AnyImmediatePublisher<String, Never> {
Just("Alice").eraseToAnyImmediatePublisher()
}
Don't miss Basic Immediate Publishers for some handy shortcuts. The above publisher can be written as:
func namePublisher() -> AnyImmediatePublisher<String, Never> {
.just("Alice")
}
In order to benefit from the ImmediatePublisher
protocol, you need a concrete publisher that conforms to this protocol.
There are a few ways to get such a immediate publisher:
-
Compiler-checked immediate publishers are publishers that conform to the
ImmediatePublisher
protocol. This is the case ofJust
andFail
, for example. Some publishers conditionally conform toImmediatePublisher
, such asPublishers.Map
, when the upstream publisher is a immediate publisher.When you define a publisher type that publishes a value or fails, right on subscription, you can turn it into a immediate publisher with an extension:
struct MyImmediatePublisher: Publisher { ... } extension MyImmediatePublisher: ImmediatePublisher { } let immediatePublisher = MyImmediatePublisher().eraseToAnyImmediatePublisher() let cancellable = MyImmediatePublisher().sinkImmediate { result in ... }
-
Runtime-checked immediate publishers are publishers that conform to the
ImmediatePublisher
protocol by checking, at runtime, that an upstream publisher publishes a value or fails, right on subscription.Publisher.assertImmediate()
returns a immediate publisher that raises a fatal error if the upstream publisher does not honor the contract.For example:
let nameSubject: PassthroughSubject<String, Never> = ... func namePublisher() -> AnyImmediatePublisher<String, Never> { subject.prepend("Unknown").assertImmediate().eraseToAnyImmediatePublisher() }
-
Unchecked immediate publishers: you should only build such a immediate publisher when you are sure that the
ImmediatePublisher
contract is honored by the upstream publisher.For example:
// CORRECT: those publish a value or fail, right on subscription. [1].publisher.uncheckedImmediate() [1, 2].publisher.prefix(1).uncheckedImmediate() // WRONG: does not publish any value, does not fail. Empty().uncheckedImmediate()
The consequences of using
uncheckedImmediate()
on a publisher that does not publish a value or fail, right on subscription, are undefined.
See also Basic Immediate Publishers.
AnyImmediatePublisher
comes with factory methods that build basic immediate publishers:
// Publishes one value, and then completes.
AnyImmediatePublisher.just(value)
// Fails with the given error.
AnyImmediatePublisher.fail(error)
They are quite handy:
func namePublisher() -> AnyImmediatePublisher<String, Error> {
.just("Alice")
}