I am trying to implement a subscriber which specifies its own demand for how many elements it wants to receive from a publisher.
My code is below:
import Combine
var array = [1, 2, 3, 4, 5, 6, 7]
struct ArraySubscriber<T>: Subscriber {
typealias Input = T
typealias Failure = Never
let combineIdentifier = CombineIdentifier()
func receive(subscription: any Subscription) {
subscription.request(.max(4))
}
func receive(_ input: T) -> Subscribers.Demand {
print("input,", input)
return .max(4)
}
func receive(completion: Subscribers.Completion<Never>) {
switch completion {
case .finished:
print("publisher finished normally")
case .failure(let failure):
print("publisher failed due to, ", failure)
}
}
}
let subscriber = ArraySubscriber<Int>()
array.publisher.subscribe(subscriber)
According to Apple's documentation, I specify the demand inside the receive(subscription: any Subscription) method, see link.
But when I run this code I get the following output:
input, 1
input, 2
input, 3
input, 4
input, 5
input, 6
input, 7
publisher finished normally
Instead, I expect the subscriber to only "receive" elements 1, 2, 3, 4
from the array.
How can I accomplish this?
The publisher not only asks you for your desired demand in receive(subscription:)
, but also after every time the subscriber receives an element, in receive(_:)
.
Your code says you always want max 4 more elements after receiving every element:
func receive(_ input: T) -> Subscribers.Demand {
print("input,", input)
return .max(4)
}
If you only ever want to receive 4 elements, you should return .none
in this method.
func receive(_ input: T) -> Subscribers.Demand {
print("input,", input)
return .none // <-----
}
The output now becomes:
input, 1
input, 2
input, 3
input, 4
An alternative implementation is to keep a count of how many more elements you want, and always demanding 1 element each time. Example:
var remainingElements = 4
func receive(subscription: any Subscription) {
subscription.request(.max(1))
}
func receive(_ input: T) -> Subscribers.Demand {
print("input,", input)
remainingElements -= 1
return remainingElements > 0 ? .max(1) : .none
}
Depending on the publisher, the behaviour may or may not be different. For example, some publishers might eagerly produce more elements if you request .max(4)
at the beginning.