英文:
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) ->URLRequest? {
guard var urlComponents = URLComponents(string:client.baseUrl + client.path) else {
return nil
}
urlComponents.query = "\(client.params)"
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<T:Codable>(client: ServiceClient, type:T.Type) -> AnyPublisher<T,ServiceError> {
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 ..
答案1
得分: 1
问题在于你试图返回一个Publisher
,其Failure
类型为ServiceError
,但是你的Combine管道也可以抛出其他错误类型。tryMap
的Failure
类型是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 -> 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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论