Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Combine: How to specify the Error type of tryMap(_:)?

In the Combine framework, we can throw a generic Error protocol type while using tryMap.

However, how can we be more specific about the Error type?

For example,

let publisher = urlSession.dataTaskPublisher(for: request).tryMap { (data, response) -> (Data, HTTPURLResponse) in
      guard let response = response as? HTTPURLResponse else {
        throw URLError(.cannotParseResponse)
      }
      return (data, response)
}

How to specify the Error type of this publisher? I'd like to use URLError instead of Error.

I found the method setFailureType(to:) in the Combine framework. However, it is not available to tryMap(_:).

like image 609
WildCat Avatar asked Nov 24 '19 14:11

WildCat


Video Answer


2 Answers

setFailureType(to:) is only to force the failure type of a publisher with failure type Never. tryMap always uses Error as the error type because any Error could be thrown in the closure body, so you need to use mapError to force the URLError type:

let map_error = publisher.mapError({ error -> URLError in
    switch (error) {
    case let url_error as URLError:
        return url_error
    default:
        return URLError(.unknown)
    }
})
like image 142
Evan Deaubl Avatar answered Oct 16 '22 16:10

Evan Deaubl


You can also accomplish this with flatMap. This will allow you to specify both the Output and Error type at once, like so:

struct SomeResponseType {
    let data: Data
    let response: HTTPURLResponse
}

let publisher = urlSession.dataTaskPublisher(for: request)
    .flatMap { (data, response) -> AnyPublisher<SomeResponseType, URLError > in
      guard let response = response as? HTTPURLResponse else {
        return Fail(error: URLError(.cannotParseResponse))
            .eraseToAnyPublisher()
      }
      return Just(SomeResponseType(data: data, response: response)
          .setFailureType(to: URLError)
          .eraseToAnyPublisher()
}
like image 30
Wiingaard Avatar answered Oct 16 '22 15:10

Wiingaard