Use the tryMap operator in Combine to transform elements from a publisher, using a throwing closure.

import Combine

enum CustomError: Error {
    case failed
}

let numbers = [2, 4, 6, 8, 9, 11]

numbers.publisher
    .tryMap { number -> Int in
        guard number % 2 == 0 else {
            throw CustomError.failed
        }
        return number
    }
    .sink { completion in
        switch completion {
        case .finished:
            print("Finished")
        case .failure(let error):
            print("Error: \(error)")
        }
    } receiveValue: { value in
        print("Value: \(value)")
    }

In the above code:

  1. The numbers array is converted to a publisher using the publisher property.
  2. The tryMap operator transforms the elements from the publisher with a throwing closure.
  3. The closure checks if the number is even, and if not, throws a custom error.
  4. The sink operator subscribes to the publisher and prints the emitted values or errors.

When you run the code, you will see the following output:

Value: 2
Value: 4
Value: 6
Value: 8
Error: failed

The tryMap operator is useful when you need to transform elements from a publisher with a throwing closure and handle any errors that occur during the transformation process.

The operator will stop the publisher chain and emit the error if the closure throws an error.

If a function or a closure has the same signature as the closure passed to tryMap, you can directly pass the function or closure to the tryMap operator. This can make the code more readable and concise.

// ...
func isEven(number: Int) throws -> Int {
    guard number % 2 == 0 else {
        throw CustomError.failed
    }
    return number
}

numbers.publisher
    .tryMap(isEven)
// ...

If the function or closure does not have the same signature, you can still call if from the tryMap operator by using the closure syntax.

// ...
func isEven(number: Int) throws -> Int {
    guard number % 2 == 0 else {
        throw CustomError.failed
    }
    return number
}

numbers.publisher
    .tryMap { try isEven(number: $0) }
// ...