Cannot convert return expression of type ‘AnyPublisher‘ in Combine.

huangapple go评论62阅读模式
英文:

Cannot convert return expression of type 'AnyPublisher<T, any Error> in Combine

问题

无法将类型为 'AnyPublisher<T, any Error>' 的返回表达式转换为类型为 'AnyPublisher<T, ServiceError>' 的返回类型。

英文:

I am new to combine . I created an generic function which return AnyPublisher with result (T) and Error(Service error) it the custom error message . I have the pass the urlSession with dataTaskPublisher and return the request. I am getting following error ..

Cannot convert return expression of type 'AnyPublisher<T, any Error>' to return type 'AnyPublisher<T, ServiceError>'

Here is the code for URL request.

extension URLRequest {
    static func getRequest(client: ServiceClient) -&gt;URLRequest? {
        guard var urlComponents = URLComponents(string:client.baseUrl + client.path) else {
            return nil
        }
        urlComponents.query = &quot;\(client.params)&quot;
        guard let url = urlComponents.url else {
            return nil
        }
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = client.method
        return urlRequest
    }
}

Here is the code ..

class ServiceImpl: Service {

    let urlSesson = URLSession(configuration: .default)
    var dataTask: URLSessionDataTask?

    func fetchData&lt;T:Codable&gt;(client: ServiceClient, type:T.Type) -&gt; AnyPublisher&lt;T,ServiceError&gt; {

        guard let request = URLRequest.getRequest(client: client) else {
            return Fail(outputType: type, failure: ServiceError.requestNotCreated(message: Constants.requestNotCreated)).eraseToAnyPublisher()
        }
        return urlSesson.dataTaskPublisher(for: request)
            .tryMap {
                guard let response = $0.response as? HTTPURLResponse, response.statusCode == 200 else {
                    throw ServiceError.errorWith(message: Constants.noResponse)
                }
                return $0.data
            }
            .decode(type: T.self, decoder: JSONDecoder())
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()
    }
}

Here is the screenshot of the error ..

Cannot convert return expression of type ‘AnyPublisher<T, any Error>‘ in Combine.

答案1

得分: 1

问题在于你试图返回一个Publisher,其Failure类型为ServiceError,但是你的Combine管道也可以抛出其他错误类型。tryMapFailure类型是any Error,与decode相同。

为了解决这个问题,你需要调用mapError,以确保在出现Failure时始终发出ServiceError

      ...
      .receive(on: RunLoop.main)
      .mapError { error -> ServiceError in
        switch error {
        case let serviceError as ServiceError:
          return serviceError
        default:
          return .generic(error)
        }
      }
      .eraseToAnyPublisher()

上面的代码假设你的ServiceError有一个generic(Error)的case。你也可以返回其他任何case,我只是用这个作为示例,因为你在问题中没有实际包含ServiceError的定义。

英文:

The problem is that you are trying to return a Publisher whose Failure type is ServiceError, but your Combine pipeline can throw other error types as well. tryMap's Failure type is any Error, same as decode's.

To resolve the problem, you need to call mapError to ensure that you are always emitting a ServiceError in case of Failure.

  ...
  .receive(on: RunLoop.main)
  .mapError { error -&gt; ServiceError in
    switch error {
    case let serviceError as ServiceError:
      return serviceError
    default:
      return .generic(error)
    }
  }
  .eraseToAnyPublisher()

Above code assumes that your ServiceError has a generic(Error) case. You can return any other case as well, I've just used this as an example since you haven't actually included your ServiceError definition in your question.

enum ServiceError: Error {
  case errorWith(message: String)
  case generic(Error)
}

huangapple
  • 本文由 发表于 2023年3月10日 00:27:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定