Just
A publisher that emits an output to each subscriber just once and then finishes. Generic only over the output since can not fail.
let justPublisher = Just<String>("one value") //Just.init(<#T##output: _##_#>)
let cancellable = justPublisher.sink(receiveCompletion: { result in
print(result)
}, receiveValue: { value in
print(value)
})
let cancellable2 = justPublisher.sink(receiveCompletion: { result in
print(result)
}, receiveValue: { value in
print(value)
})
The output is:
one value
finished
one value
finished
The publisher emits one value to each subscriber and then finishes with no error.
Empty
A publisher that never publishes any values and optionally finishes immediately. It can be useful when we need to return a publisher that will never emit any value.
//Empty.init(completeImmediately: Bool, outputType: <#T##_.Type#>, failureType: <#T##_.Type#>)
let cancellable = Empty<String, Never>()
.sink { value in
print(value)
}
No output is produced.
Fail
A Fail
publisher immediately terminates with the specified error. No values were emitted.
//Fail.init(error: <#T##_#>)
//Fail.init(outputType: <#T##_.Type#>, failure: <#T##_#>)
enum AnyError: Error {
case any
case future
case record
}
let cancellable = Fail(error: AnyError.any)
.sink(receiveCompletion: { result in
print("result:", result)
}, receiveValue: { value in
print(value)
})
Output:
result: failure(__lldb_expr_20.AnyError.any)
Future
A publisher that eventually produces a single value and then finishes or fails. It’s an eager publisher, which means that the code inside the closure it’s executed even when no one it’s subscribed yet. The callback parameter is like a promise that we need to fulfill with a value or an error.
// Future.init(<#T##attemptToFulfill: (@escaping Future<_, _>.Promise) -> Void##(@escaping Future<_, _>.Promise) -> Void#>)
let futurePublisher = Future<String, Never> { callback in
print("code executed")
callback(.success("Some message"))
callback(.success("Another message"))
//callback(.failure(<#T##Never#>))
}
We can see “code executed” is printed in the console even when no one is subscribed yet. If someone is subscribed:
let cancellable = futurePublisher.sink { value in
print(value)
}
The full output will be:
code executed
Some message
We can see after a subscription, the code in the closure is not executed again, just deliver the result computed previously. As we can see, only the first message was delivered because we can only send one result to the callback.
Deferred
A publisher that awaits a subscription before running the supplied closure to create a publisher for the new subscriber. It’s a lazy publisher, which means the closure will not be executed until someone is subscribed. We can use this to wrap a Future publisher when we want the closure is not executed until someone subscribe.
let deferredPublisher = Deferred {
Future<String, Never> { callback in
print("defered code executed")
callback(.success("Some defered message"))
}
}
No output will be emitted until someone subscribes:
let cancellable = deferredPublisher.sink { value in
print(value)
}
Then the output will be:
defered code executed
Some defered message
Record
Allow us to specify a list of values that will be emitted when someone subscribes and the completion result.
// Record.init(output: <#T##[_]#>, completion: <#T##Subscribers.Completion<_>#>)
let recordPublisher = Record<String, AnyError>(output: ["hello", "word", "another output"], completion: .failure(.record))
let cancellable = recordPublisher.sink(receiveCompletion: { result in
print(result)
}, receiveValue: { value in
print(value)
})
The output will be:
hello
word
another output
failure(__lldb_expr_34.AnyError.record)
Subjects (protocol)
A publisher exposes a method for outside callers to publish elements. A subject is a publisher that you can use to ”inject” values into a stream by calling its send(_:) method. It can be useful for adapting existing imperative code to the Combine model. We have two types of subjects: PassthroughSubject
and CurrentValueSubject
PassthroughSubject
A PassthroughSubject
drops values if there are no subscribers or its current demand is zero. Unlike CurrentValueSubject
, it doesn’t have an initial value or buffer of the most recently-published element
let passthrough = PassthroughSubject<String, Never>()
passthrough.send("first value")
let cancellable = passthrough.sink { value in
print(value)
}
passthrough.send("second value")
passthrough.send(completion: .finished)
The output will be:
As we can see, the first element “first value” was dropped since no one was subscribed when the value was emitted.
CurrentValueSubject
A subject that wraps a single value and publishes a new element whenever the value changes. Need an initial value. When someone subscribes, emit the most recent value.
//CurrentValueSubject.init(<#T##value: _##_#>)
let current = CurrentValueSubject<String, Never>("current one")
let cancellable = current.sink { value in
print(value)
}
print("reading value:", current.value)
//To published values, we can send or set the value property
current.send("current two")
current.value = "current three"
The output will be:
current one
reading value: current one
current two
current three
We can access the current value with the value property. We have two ways of publishing a new element: using the send method or modifying the value property.