iTranslated by AI
[Swift][Combine] Combine Streams Stop Accepting Outputs After cancel() or send(completion:)
What this article covers
- Combine streams do not accept further outputs once
cancel()orsend(completion:)is received.
Experiment (1): In the case of cancel()
Prerequisites
Prepare the sample code as shown below.
The key point here is adding a delay to the map() process.
import Combine
import Foundation
var cancellables = Set<AnyCancellable>()
let numPublisher: PassthroughSubject<Int, Error> = .init()
numPublisher
.handleEvents(receiveOutput: {
print("receiveRequest: \($0)")
}, receiveCancel: {
print("receiveCancel")
})
.map { num -> Int in
Thread.sleep(forTimeInterval: 3.0) // Delay process
return num
}
.sink { result in
switch result {
case .finished:
print("finished")
case let .failure(error):
print("failure: \(error)")
}
} receiveValue: { value in
print("receiveValue: \(value)")
}
.store(in: &cancellables)
Experiment Details
In this state, I will execute the following:
- Output from
numPublisher -
cancel()oncancellables - Output from
numPublisher
// 1. Output from `numPublisher`
numPublisher.send(1)
numPublisher.send(2)
// 2. `cancel()` on `cancellables`
cancellables.map { $0.cancel() }
// 3. Output from `numPublisher`
numPublisher.send(3)
Verification Point
Because I added a 3-second delay in map(), I will confirm how the output in '3. Output from numPublisher' is handled, given that '1. Output from numPublisher' has not yet reached receiveValue at the moment '2. cancel() on cancellables' is executed.
Output Results
The results were as follows:
// (Output)
// receiveRequest: 1
// receiveValue: 1
// receiveRequest: 2
// receiveValue: 2
// receiveCancel
↑
`numPublisher.send(3)` was not accepted!!
As shown, it is clear that the '3. Output from numPublisher' was not accepted.
What this implies
- Combine streams do not accept outputs once they have received
cancel().
Experiment (2): In the case of send(completion:)
I will verify what happens when send(completion:) of the Publisher is performed instead of cancel().
In the case of send(completion: .finished)
// 1. Output from `numPublisher`
numPublisher.send(1)
numPublisher.send(2)
// 2. `send(completion:)` of `numPublisher`
numPublisher.send(completion: .finished)
// 3. Output from `numPublisher`
numPublisher.send(3)
// (Output)
// receiveRequest: 1
// receiveValue: 1
// receiveRequest: 2
// receiveValue: 2
// finished
↑
`numPublisher.send(3)` was not accepted!!
Similar to cancel(), it is clear that the '3. Output from numPublisher' was not accepted.
In the case of send(completion: .failure())
enum TestError: Error {
case testError
}
// 1. Output from `numPublisher`
numPublisher.send(1)
numPublisher.send(2)
// 2. `send(completion:)` of `numPublisher`
numPublisher.send(completion: .failure(TestError.testError))
// 3. Output from `numPublisher`
numPublisher.send(3)
// (Output)
// receiveRequest: 1
// receiveValue: 1
// receiveRequest: 2
// receiveValue: 2
// failure: testError
↑
`numPublisher.send(3)` was not accepted!!
Again, similar to cancel(), it is clear that the '3. Output from numPublisher' was not accepted.
Summary
- Combine streams do not accept further outputs once
cancel()orsend(completion:)is received.
That is all.
Discussion