Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use CombineLates when when publishers failure types is not equivalent?

Tags:

swift

combine

I have two functions which return AnyPublisher with different failure type: Never and Error. When using these functions in the CombineLates, then compilation fails with an error: Generic struct 'CombineLatest' requires the types 'Error' and 'Never' be equivalent

Function which never fails:

func foo() -> AnyPublisher<Int, Never> {
    Result<Int, Never>
        .success(1).publisher
        .eraseToAnyPublisher()
}

Function which sometimes fails:

func boo() -> AnyPublisher<Int, Error> {
    Result<Int, Error>
        .failure(NSError(domain: "d", code: -1))
        .publisher.eraseToAnyPublisher()
}

foo & boo functions usage:

Publishers.CombineLatest(foo(), boo())

Error generated:

Generic struct 'CombineLatest' requires the types 'Error' and 'Never' be equivalent

How to use CombineLates when publisher's failure types are not equivalent?

like image 700
Ramis Avatar asked Oct 19 '25 14:10

Ramis


2 Answers

Whenever you need to match failure types in Combine, for a Never failure type, like a Just publisher, you'd use setFailureType(to:):

let p: AnyPublisher<Int, Never> = ...

let p1 = p.setFailureType(to: Error.self)
          .eraseToAnyPublisher()  // AnyPublisher<Int, Error>

For a non-Never failure, you'd need to use .mapError:

let p2 = p1.mapError { CustomError(wrapping: $0) }
           .eraseToAnyPublisher() // AnyPublisher<Int, CustomError> 

So, in your case, if you want to change foo's return value, you'd do:

func foo() -> AnyPublisher<Int, Error> {
    Result<Int, Never>
        .success(1).publisher
        .setFailureType(to: Error.self)
        .eraseToAnyPublisher()
}

And if you don't want to change foo, but still use with with bar, you can do:

Publishers.CombineLatest(foo().setFailureType(to: Error.self), boo())
   .map { (f, b) in
     // f and b are Ints, as emitted by foo and bar, respectively
   }
like image 87
New Dev Avatar answered Oct 22 '25 02:10

New Dev


You can use setFailureType(to:) to set the error type of the publisher that never fails, to match the other publisher that does fail:

func foo() -> AnyPublisher<Int, Never> {
    Result<Int, Never>
        .success(1).publisher
        .setFailureType(to: Error.self)
        .eraseToAnyPublisher()
}

If you don't want to change foo, you can call setFailureType on the return value of foo too:

Publishers.CombineLatest(
    foo().setFailureType(to: Error.self).eraseToAnyPublisher(), 
    boo()
)
like image 24
Sweeper Avatar answered Oct 22 '25 02:10

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!