合并多个错误处理

Combine multiple errors handling

我决定将标准网络调用迁移到使用 combine 及其运算符的调用。

给定以下代码

enum NetworkServiceError: Error{
   case badUrl
   case networkFail(String)
}

func getHtml(from url: String, completion: @escaping (Result<String, NetworkServiceError>) -> ()) {
   guard let url = URL(string: url) else {
      completion(.failure(.badUrl))
      return
   }
   URLSession.shared.dataTask(with: url) { (data, _, error) in
      if let err = error{
         completion(.failure(.networkFail(err.localizedDescription)))
         return
      }
      guard let rawHtmlData = data else {
         completion(.failure(.networkFail("No data")))
         return
      }
      guard let html = String(data: rawHtmlData, encoding: .utf8) else {
         completion(.failure(.networkFail("String serialization failed")))
         return
      }
      completion(.success(html))
   }
   .resume()
}

我希望在 combine 对应物中有同样精确的错误处理。 老实说,尽管我看了很多关于联合收割机的视频,但我还是不知道该怎么做。 这是我的尝试

func combineHtml(url: String)-> AnyPublisher<String, NetworkServiceError>{
   
   guard let safeUrl = URL(string: url) else {
      return Fail(error: NetworkServiceError.badUrl).eraseToAnyPublisher()
   }

   let publisher = URLSession.shared
      .dataTaskPublisher(for: safeUrl)
      .tryMap{ result-> Data in
         guard !result.data.isEmpty else{throw NetworkServiceError.networkFail("No data")}
         return result.data
      }
      .tryMap{ data-> String in
         guard let html = String(data: data, encoding: .utf8) else{
            throw NetworkServiceError.networkFail("String serialization failed")
         }
         return html
      }
//      .mapError{ error-> NetworkServiceError in
//         return NetworkServiceError.networkFail("error")
//      }

 
      .receive(on: DispatchQueue.main)
      .eraseToAnyPublisher()
      
   return publisher
      
}

我不确定我应该如何处理不同的错误:try 运算符应该抛出并且管道应该取消,这正是我想要的。但是,如果我不将错误映射到 NetworkServiceError,(注释代码)我应该更改我想避免的 return 类型。 我的错误处理一定有不正确的地方。

在 combine 中处理多个错误的最佳方法是什么? 我对这段代码不是很满意。

我设法解决了这个问题。 我将post相关部分代码,其余不变

.tryMap{ result-> String in
         guard !result.data.isEmpty else{throw NetworkServiceError.networkFail("No data")}
         guard let html = String(data: result.data, encoding: .utf8) else{
            throw NetworkServiceError.networkFail("String serialization failed")
         }
         return html
      }
.mapError{error-> NetworkServiceError in
   if let customError = error as? NetworkServiceError{
       return customError
    }
    return NetworkServiceError.networkFail(error.localizedDescription)
}

mapError 运算符是实现类型要求所必需的。在 tryMap 中,我们可以抛出所有需要的错误,因为我们将在 mapError 闭包中捕获它们