Swift 当响应数据不包含要使用Combine进行解码的对象时,如何抛出错误?

Swift 当响应数据不包含要使用Combine进行解码的对象时,如何抛出错误?,swift,combine,throw,Swift,Combine,Throw,我有一个发布者包装结构,可以在其中处理响应状态代码。如果状态代码不在200..300范围内,它将返回一个对象,否则将抛出一个错误。它工作得很好 public func anyPublisher<T:Decodable>(type: T.Type) -> AnyPublisher<T, Error> { return URLSession.shared.dataTaskPublisher(for: urlRequest) .tryMap { o

我有一个发布者包装结构,可以在其中处理响应状态代码。如果状态代码不在200..300范围内,它将返回一个对象,否则将抛出一个错误。它工作得很好

public func anyPublisher<T:Decodable>(type: T.Type) -> AnyPublisher<T, Error> {
    return URLSession.shared.dataTaskPublisher(for: urlRequest)
        .tryMap { output in
            guard let httpResponse = output.response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
                throw APIError.unknown
            }
            return output.data
    }
    .decode(type: T.self, decoder: JSONDecoder())
    .receive(on: DispatchQueue.main)
    .eraseToAnyPublisher()
}
如上所述,即使响应数据不包含要解码的对象,我也希望处理错误

public func anyPublisher() -> AnyPublisher<URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure> {
    return URLSession.shared.dataTaskPublisher(for: urlRequest)
        // I'd like to handle status code here, and throw an error, if needed
        .receive(on: DispatchQueue.main)
        .eraseToAnyPublisher()
}
public func anyPublisher()->anyPublisher{
返回URLSession.shared.dataTaskPublisher(用于:urlRequest)
//我想在这里处理状态代码,如果需要,抛出一个错误
.receive(在:DispatchQueue.main上)
.删除任何发布者()
}

提前感谢您提供的任何帮助。

我建议创建一个处理HTTP响应状态代码验证的发布者,并将其用于其他两个发布者—处理空请求正文的发布者和解码正文的发布者

如果在验证其状态代码后仍需要
HTTPURLResponse
对象:

extension URLSession.DataTaskPublisher {
    /// Publisher that throws an error in case the data task finished with an invalid status code, otherwise it simply returns the body and response of the HTTP request
    func httpResponseValidator() -> AnyPublisher<Output, CustomError> {
        tryMap { data, response in
            guard let httpResponse = response as? HTTPURLResponse else { throw CustomError.nonHTTPResponse }
            let statusCode = httpResponse.statusCode
            guard (200..<300).contains(statusCode) else { throw CustomError.incorrectStatusCode(statusCode) }
            return (data, httpResponse)
        }
        .mapError { CustomError.network($0) }
        .eraseToAnyPublisher()
    }
}

也许我不明白这个问题?为什么不能像上面那样使用
tryMap
,并检查
$0.data
是否为零?因为我知道数据将为零!例如,当REST请求的响应(如DELETE方法)不包含body,而只包含一个状态代码时,让我们看看这种情况。在这种情况下,我不想返回任何内容,但我喜欢抛出一个异常,如果状态代码不是200,我想我仍然感到困惑。您有一个a函数,该函数应该返回具有
URLSession.DataTaskPublisher.Output
值的发布服务器,该值是
(数据,urresponse)
元组。如果你说你知道数据为零,这就是你想要的吗?(顺便说一句,如果请求失败,数据只有零)我有两个功能:一个是有数据要编码的人,另一个是数据为空的人!你说得对!我用了一个词!所以数据不是零,而是空的!我创建了一个简单的项目,在这里您可以看到:。您可以在AddDeletePostViewModel.swift中看到NetworkPublisher结构之间的差异。太棒了!超级优雅的解决方案!这正是我需要的//Nagyon szépen Köszönöm!!;)
extension URLSession.DataTaskPublisher {
    /// Publisher that throws an error in case the data task finished with an invalid status code, otherwise it simply returns the body and response of the HTTP request
    func httpResponseValidator() -> AnyPublisher<Output, CustomError> {
        tryMap { data, response in
            guard let httpResponse = response as? HTTPURLResponse else { throw CustomError.nonHTTPResponse }
            let statusCode = httpResponse.statusCode
            guard (200..<300).contains(statusCode) else { throw CustomError.incorrectStatusCode(statusCode) }
            return (data, httpResponse)
        }
        .mapError { CustomError.network($0) }
        .eraseToAnyPublisher()
    }
}
func httpResponseValidator() -> AnyPublisher<Data, CustomError> {
    tryMap { data, response in
        guard let httpResponse = response as? HTTPURLResponse else { throw CustomError.nonHTTPResponse }
        let statusCode = httpResponse.statusCode
        guard (200..<300).contains(statusCode) else { throw CustomError.incorrectStatusCode(statusCode) }
        return data
    }
    .mapError { CustomError.network($0) }
    .eraseToAnyPublisher()
}
extension URLSession.DataTaskPublisher {
    func anyPublisher<T:Decodable>(type: T.Type) -> AnyPublisher<T, Error> {
        httpResponseValidator()
            .decode(type: T.self, decoder: JSONDecoder())
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }

    func anyPublisher() -> AnyPublisher<Output, CustomError> {
        httpResponseValidator()
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }
}