Skip to content

Instantly share code, notes, and snippets.

Created July 11, 2020 01:52
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
import Foundation
import Combine
// Publishers are a namespace for types that serve as publishers.
// "The various operators defined as extensions on ``Publisher`` implement their functionality as classes or structures that extend this enumeration. For example, the `contains(_:)` operator returns a `Publishers.Contains` instance."
// ```
// public enum Publishers {
// }
// It's basically `Output` or what token is produced at each receive, `Failure`
// which is the error type (using `Never` for error-free streaming), and `receive<S>(subscriber:<S>)`
// The generic references `Subscriber`, which has a `Failure` and `Input` type. The errors must agree
// as must the Input/Output.
public protocol Publisher {
/// The kind of values published by this publisher.
associatedtype Output
/// The kind of errors this publisher might publish.
/// Use `Never` if this `Publisher` does not publish errors.
associatedtype Failure : Error
/// 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.
func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
// `Strings` are `Sequences`, so `Strings` have a publisher
let str = "Hello, playground"
// var publisher: Publishers.Sequence<String, Never> { get }
let strpub = str.publisher
// The sequence defines what kind of `Output` it publishes, and what `Input` its subscribers receive:
// public typealias Output = Elements.Element
// Or, basically, the stream `Element` is the `Output` in this case.
// This particular publisher stores a sequence internally so it can be referenced and used
// and it defines an initializer that supports this:
// `public let sequence: Elements`
// This isn't magic, it's an implementation detail that has to be public
// Finally, it attaches a subscriber to the publisher so it can
// receive values:
// `public func receive<S>(subscriber: S) where Failure == S.Failure, S : Subscriber, Elements.Element == S.Input`
// Note: each implementations of ``Publisher`` must implement this method, which varies by type.
// A publisher has a type and a "Failure"/Error
// `struct Sequence<Elements, Failure> : Publisher`
// ` where Elements : Sequence, Failure : Error`
// `Publishers.Sequence`
// ## SINKS
// A `sink` creates a subscriber where the values are pulled in.
// Definition: "a body or process which acts to absorb or remove energy or a particular component from a system"
// Can be rewritten: "a request which acts to process data streamed from a publisher"
// The sink takes one or two arguments
// It creates a subscriber, a cancellable `Combine.AnyCancellable`
/// This method creates the subscriber and immediately requests an unlimited number of values, prior to returning the subscriber.
/// The return value should be held, otherwise the stream will be canceled.
/// - parameter receiveComplete: The closure to execute on completion.
/// - parameter receiveValue: The closure to execute on receipt of a value.
/// - Returns: A cancellable instance, which you use when you end assignment of the received value. Deallocation of the result will tear down the subscription stream.
public func sink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
// Create a sink and populate its two handlers. Notice that the completion handler when used comes first.
let stream = strpub.sink { completionInfo in
} receiveValue: { stringElement in
print(stringElement, "received")
print("Stream: \(stream)")
// Each sink produces a separate pass on the publisher. So this can be run again.
let stream2 = strpub.sink { completionInfo in
} receiveValue: { stringElement in
print(stringElement, "received")
print("Stream2: \(stream2)")
// You don't need to store the receiver/subscriber if you won't be cancelling.
// Here's the short form:
_ = strpub.sink { print($0) }
// the completion is `Subscribers.Completion<Failure>`
// That looks like this:
@frozen public enum Completion<Failure> where Failure : Error {
/// The publisher finished normally.
case finished
/// The publisher stopped publishing due to the indicated error.
case failure(Failure)
// So there are exactly two states this can end in: finished or failure. Some publishers
// go on forever, so their output stream never finishes except in error (if an error is supported).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment