Combine: Publisher

Publisher

The publisher is the provider of data.

Empty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/// A publisher that never publishes any values, and optionally finishes immediately.
///
/// You can create a ”Never” publisher — one which never sends values and never finishes or fails — with the initializer `Empty(completeImmediately: false)`.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Empty<Output, Failure> : Publisher, Equatable where Failure : Error {

/// Creates an empty publisher.
///
/// - Parameter completeImmediately: A Boolean value that indicates whether the publisher should immediately finish.
public init(completeImmediately: Bool = true)

/// Creates an empty publisher with the given completion behavior and output and failure types.
///
/// Use this initializer to connect the empty publisher to subscribers or other publishers that have specific output and failure types.
///
/// - Parameters:
/// - completeImmediately: A Boolean value that indicates whether the publisher should immediately finish.
/// - outputType: The output type exposed by this publisher.
/// - failureType: The failure type exposed by this publisher.
public init(completeImmediately: Bool = true, outputType: Output.Type, failureType: Failure.Type)

/// A Boolean value that indicates whether the publisher immediately sends a completion.
///
/// If `true`, the publisher finishes immediately after sending a subscription to the subscriber. If `false`, it never completes.
public let completeImmediately: Bool

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
public func receive<S>(subscriber: S) where Output == S.Input, Failure == S.Failure, S : Subscriber

/// Returns a Boolean value that indicates whether two publishers are equivalent.
/// - Parameters:
/// - lhs: An `Empty` instance to compare.
/// - rhs: Another `Empty` instance to compare.
/// - Returns: `true` if the two publishers have equal `completeImmediately` properties; otherwise `false`.
public static func == (lhs: Empty<Output, Failure>, rhs: Empty<Output, Failure>) -> Bool
}

Just

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// A publisher that emits an output to each subscriber just once, and then finishes.
///
/// You can use a ``Just`` publisher to start a chain of publishers. A ``Just`` publisher is also useful when replacing a value with ``Publishers/Catch``.
///
/// In contrast with <doc://com.apple.documentation/documentation/Swift/Result/Publisher>, a ``Just`` publisher can’t fail with an error. And unlike <doc://com.apple.documentation/documentation/Swift/Optional/Publisher>, a ``Just`` publisher always produces a value.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Just<Output> : Publisher {

/// The kind of errors this publisher might publish.
///
/// Use `Never` if this `Publisher` does not publish errors.
public typealias Failure = Never

/// The one element that the publisher emits.
public let output: Output

/// Initializes a publisher that emits the specified output just once.
///
/// - Parameter output: The one element that the publisher emits.
public init(_ output: Output)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
public func receive<S>(subscriber: S) where Output == S.Input, S : Subscriber, S.Failure == Just<Output>.Failure
}

Future

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// A publisher that eventually produces a single value and then finishes or fails.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
final public class Future<Output, Failure> : Publisher where Failure : Error {

/// A type that represents a closure to invoke in the future, when an element or error is available.
///
/// The promise closure receives one parameter: a `Result` that contains either a single element published by a ``Future``, or an error.
public typealias Promise = (Result<Output, Failure>) -> Void

/// Creates a publisher that invokes a promise closure when the publisher emits an element.
///
/// - Parameter attemptToFulfill: A ``Future/Promise`` that the publisher invokes when the publisher emits an element or terminates with an error.
public init(_ attemptToFulfill: @escaping (@escaping Future<Output, Failure>.Promise) -> Void)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
final public func receive<S>(subscriber: S) where Output == S.Input, Failure == S.Failure, S : Subscriber
}

Deferrred

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/// A publisher that awaits subscription before running the supplied closure to create a publisher for the new subscriber.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Deferred<DeferredPublisher> : Publisher where DeferredPublisher : Publisher {

/// The kind of values published by this publisher.
public typealias Output = DeferredPublisher.Output

/// The kind of errors this publisher might publish.
public typealias Failure = DeferredPublisher.Failure

/// The closure to execute when this deferred publisher receives a subscription.
///
/// The publisher returned by this closure immediately receives the incoming subscription.
public let createPublisher: () -> DeferredPublisher

/// Creates a deferred publisher.
///
/// - Parameter createPublisher: The closure to execute when calling `subscribe(_:)`.
public init(createPublisher: @escaping () -> DeferredPublisher)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
public func receive<S>(subscriber: S) where S : Subscriber, DeferredPublisher.Failure == S.Failure, DeferredPublisher.Output == S.Input
}

Fail

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// A publisher that immediately terminates with the specified error.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Fail<Output, Failure> : Publisher where Failure : Error {

/// Creates a publisher that immediately terminates with the specified failure.
///
/// - Parameter error: The failure to send when terminating the publisher.
public init(error: Failure)

/// Creates publisher with the given output type, that immediately terminates with the specified failure.
///
/// Use this initializer to create a `Fail` publisher that can work with subscribers or publishers that expect a given output type.
///
/// - Parameters:
/// - outputType: The output type exposed by this publisher.
/// - failure: The failure to send when terminating the publisher.
public init(outputType: Output.Type, failure: Failure)

/// The failure to send when terminating the publisher.
public let error: Failure

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
public func receive<S>(subscriber: S) where Output == S.Input, Failure == S.Failure, S : Subscriber
}

Sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
extension Publishers {

/// A publisher that publishes a given sequence of elements.
///
/// When the publisher exhausts the elements in the sequence, the next request causes the publisher to finish.
public struct Sequence<Elements, Failure> : Publisher where Elements : Sequence, Failure : Error {

/// The kind of values published by this publisher.
public typealias Output = Elements.Element

/// The sequence of elements to publish.
public let sequence: Elements

/// Creates a publisher for a sequence of elements.
///
/// - Parameter sequence: The sequence of elements to publish.
public init(sequence: Elements)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
public func receive<S>(subscriber: S) where Failure == S.Failure, S : Subscriber, Elements.Element == S.Input
}
}

Record

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/// A publisher that allows for recording a series of inputs and a completion, for later playback to each subscriber.
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct Record<Output, Failure> : Publisher where Failure : Error {

/// The recorded output and completion.
public let recording: Record<Output, Failure>.Recording

/// Creates a publisher to interactively record a series of outputs and a completion.
///
/// - Parameter record: A recording instance that can be retrieved after completion to create new record publishers to replay the recording.
public init(record: (inout Record<Output, Failure>.Recording) -> Void)

/// Creates a record publisher from an existing recording.
///
/// - Parameter recording: A previously-recorded recording of published elements and a completion.
public init(recording: Record<Output, Failure>.Recording)

/// Creates a record publisher to publish the provided elements, followed by the provided completion value.
///
/// - Parameters:
/// - output: An array of output elements to publish.
/// - completion: The completion value with which to end publishing.
public init(output: [Output], completion: Subscribers.Completion<Failure>)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
public func receive<S>(subscriber: S) where Output == S.Input, Failure == S.Failure, S : Subscriber

/// A recorded sequence of outputs, followed by a completion value.
public struct Recording {

public typealias Input = Output

/// The output which will be sent to a `Subscriber`.
public var output: [Output] { get }

/// The completion which will be sent to a `Subscriber`.
public var completion: Subscribers.Completion<Failure> { get }

/// Set up a recording in a state ready to receive output.
public init()

/// Set up a complete recording with the specified output and completion.
public init(output: [Output], completion: Subscribers.Completion<Failure> = .finished)

/// Add an output to the recording.
///
/// A `fatalError` will be raised if output is added after adding completion.
public mutating func receive(_ input: Record<Output, Failure>.Recording.Input)

/// Add a completion to the recording.
///
/// A `fatalError` will be raised if more than one completion is added.
public mutating func receive(completion: Subscribers.Completion<Failure>)
}
}

Share

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/// A publisher that shares the output of an upstream publisher with multiple subscribers.
///
/// This publisher type supports multiple subscribers, all of whom receive unchanged elements and completion states from the upstream publisher.
///
/// > Tip: ``Publishers/Share`` is effectively a combination of the ``Publishers/Multicast`` and ``PassthroughSubject`` publishers, with an implicit ``ConnectablePublisher/autoconnect()``.
///
/// Be aware that ``Publishers/Share`` is a class rather than a structure like most other publishers. Use this type when you need a publisher instance that uses reference semantics.
final public class Share<Upstream> : Publisher, Equatable where Upstream : Publisher {

/// The kind of values published by this publisher.
///
/// This publisher uses its upstream publisher's output type.
public typealias Output = Upstream.Output

/// The kind of errors this publisher might publish.
///
/// This publisher uses its upstream publisher's failure type.
public typealias Failure = Upstream.Failure

/// The publisher from which this publisher receives elements.
final public let upstream: Upstream

/// Creates a publisher that shares the output of an upstream publisher with multiple subscribers.
/// - Parameter upstream: The publisher from which this publisher receives elements.
public init(upstream: Upstream)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
final public func receive<S>(subscriber: S) where S : Subscriber, Upstream.Failure == S.Failure, Upstream.Output == S.Input

/// Returns a Boolean value that indicates whether two publishers are equivalent.
/// - Parameters:
/// - lhs: A `Share` publisher to compare for equality.
/// - rhs: Another `Share` publisher to compare for equality.
/// - Returns: `true` if the publishers have reference equality (`===`); otherwise `false`.
public static func == (lhs: Publishers.Share<Upstream>, rhs: Publishers.Share<Upstream>) -> Bool
}

Multicast

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/// A publisher that uses a subject to deliver elements to multiple subscribers.
///
/// Use a multicast publisher when you have multiple downstream subscribers, but you want upstream publishers to only process one ``Subscriber/receive(_:)`` call per event.
final public class Multicast<Upstream, SubjectType> : ConnectablePublisher where Upstream : Publisher, SubjectType : Subject, Upstream.Failure == SubjectType.Failure, Upstream.Output == SubjectType.Output {

/// The kind of values published by this publisher.
///
/// This publisher uses its upstream publisher's output type.
public typealias Output = Upstream.Output

/// The kind of errors this publisher might publish.
///
/// This publisher uses its upstream publisher's failure type.
public typealias Failure = Upstream.Failure

/// The publisher from which this publisher receives its elements.
final public let upstream: Upstream

/// A closure that returns a subject each time a subscriber attaches to the multicast publisher.
final public let createSubject: () -> SubjectType

/// Creates a multicast publisher that applies a closure to create a subject that delivers elements to subscribers.
///
/// - Parameter createSubject: A closure that returns a ``Subject`` each time a subscriber attaches to the multicast publisher.
public init(upstream: Upstream, createSubject: @escaping () -> SubjectType)

/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
final public func receive<S>(subscriber: S) where S : Subscriber, SubjectType.Failure == S.Failure, SubjectType.Output == S.Input

/// Connects to the publisher, allowing it to produce elements, and returns an instance with which to cancel publishing.
///
/// - Returns: A ``Cancellable`` instance that you use to cancel publishing.
final public func connect() -> Cancellable
}

ConnectablePublisher

connect

某些情况下,我们希望在Publisher产生数据前对其进行相关配置,而不是当有Subscriber时,就直接开始产生数据。

Apple文档上提供了一个例子,就是当连个Subscriber要share一个DataTaskPublisher, 在正常的Publisher情况下,当第一个Subscriber进行订阅时,Task就会启动,这样有可能在第二个Subscriber订阅时,已经错过了receiveValue事件。所以我们需要ConnectablePublisher能在等待一个connect事件后,才开始产生数据,而不是有订阅就开始产生数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let url = URL(string: "https://example.com/")!
let connectable = URLSession.shared
.dataTaskPublisher(for: url)
.map() { $0.data }
.catch() { _ in Just(Data() )}
.share()
.makeConnectable()

cancellable1 = connectable
.sink(receiveCompletion: { print("Received completion 1: \($0).") },
receiveValue: { print("Received data 1: \($0.count) bytes.") })

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.cancellable2 = connectable
.sink(receiveCompletion: { print("Received completion 2: \($0).") },
receiveValue: { print("Received data 2: \($0.count) bytes.") })
}

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.connection = connectable.connect()
}

autoconnect

在某些场景下,像Timer.TimerPublisher, 每次使用前需要显示调用connect会显得很麻烦,当你根本不需要其他多余配置,或者有多个订阅者。在这种情况下,我们可以使用autoconnect。.

1
2
3
4
5
let cancellable = Timer.publish(every: 1, on: .main, in: .default)
.autoconnect()
.sink() { date in
print ("Date now: \(date)")
}