iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🌾

[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() or send(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:

  1. Output from numPublisher
  2. cancel() on cancellables
  3. Output from numPublisher
Experiment
// 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:

Results
// (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() or send(completion:) is received.

That is all.

GitHubで編集を提案

Discussion