在具有通用功能的 RestManager 中使用 flatMap 不起作用
Using flatMap in RestManager with generic function not working
我是 Combine 的新手,所以我想创建 class RestManager 用于与通用网络
获取数据 函数。函数是 returning AnyPublisher, Never> 其中 ErrorType 是 的枚举。 noInternetConnection、.empty 和 .general 例。
我尝试将 URLSession 与 dataTaskPublisher 和 flatMap
一起使用
func fetchData<T: Decodable>(url: URL) -> AnyPublisher<Result<T, ErrorType>, Never> {
URLSession
.shared
.dataTaskPublisher(for: url)
.flatMap { (data, response) -> AnyPublisher<Result<T, ErrorType>, Never> in
switch response.result {
case .success(let data):
if let data = try? JSONDecoder().decode(T.self, from: data){
return Just(data).eraseToAnyPublisher()
}
case .failure(let error):
if let error = error as? URLError {
switch error.code {
case .notConnectedToInternet, .networkConnectionLost, .timedOut:
return Fail(ErrorType.noInternetConnection).eraseToAnyPublisher()
case .cannotDecodeRawData, .cannotDecodeContentData:
return Fail(ErrorType.empty).eraseToAnyPublisher()
default:
return Fail(ErrorType.general).eraseToAnyPublisher()
}
}
}
}
.eraseToAnyPublisher()
}
但我得到了
无法将类型 'AnyPublisher<AnyPublisher<Result<T, ErrorType>, Never>.Output, URLSession.DataTaskPublisher.Failure>'(又名 'AnyPublisher<AnyPublisher<Result<T, ErrorType>, Never>.Output, URLError>')的 return 表达式转换为 return 类型 'AnyPublisher<Result<T, ErrorType>, Never>'错误。
您的实施中有几个主要流程。
首先,您不应该使用 Result
作为 Publisher
的 Output
类型和 Never
作为其 Failure
类型。您应该使用 T
作为 Output
和 ErrorType
作为 Failure
.
其次,你需要tryMap
和mapError
,而不是flatMap
。
最后,您处理 dataTaskPublisher
的结果完全错误。当 dataTaskPublisher
失败时,它会发出错误,因此您需要在 mapError
中处理它。当它成功时,它会以 data
的形式发出结果,因此您需要对其进行解码,而不是 response
.
func fetchData<T: Decodable>(url: URL) -> AnyPublisher<T, ErrorType> {
URLSession
.shared
.dataTaskPublisher(for: url)
.tryMap { data, _ in
return try JSONDecoder().decode(T.self, from: data)
}
.mapError { error -> ErrorType in
switch error {
case let urlError as URLError:
switch urlError.code {
case .notConnectedToInternet, .networkConnectionLost, .timedOut:
return .noInternetConnection
case .cannotDecodeRawData, .cannotDecodeContentData:
return .empty
default:
return .general
}
default:
return .general
}
}
.eraseToAnyPublisher()
}
我是 Combine 的新手,所以我想创建 class RestManager 用于与通用网络
获取数据 函数。函数是 returning AnyPublisher
我尝试将 URLSession 与 dataTaskPublisher 和 flatMap
一起使用func fetchData<T: Decodable>(url: URL) -> AnyPublisher<Result<T, ErrorType>, Never> {
URLSession
.shared
.dataTaskPublisher(for: url)
.flatMap { (data, response) -> AnyPublisher<Result<T, ErrorType>, Never> in
switch response.result {
case .success(let data):
if let data = try? JSONDecoder().decode(T.self, from: data){
return Just(data).eraseToAnyPublisher()
}
case .failure(let error):
if let error = error as? URLError {
switch error.code {
case .notConnectedToInternet, .networkConnectionLost, .timedOut:
return Fail(ErrorType.noInternetConnection).eraseToAnyPublisher()
case .cannotDecodeRawData, .cannotDecodeContentData:
return Fail(ErrorType.empty).eraseToAnyPublisher()
default:
return Fail(ErrorType.general).eraseToAnyPublisher()
}
}
}
}
.eraseToAnyPublisher()
}
但我得到了
无法将类型 'AnyPublisher<AnyPublisher<Result<T, ErrorType>, Never>.Output, URLSession.DataTaskPublisher.Failure>'(又名 'AnyPublisher<AnyPublisher<Result<T, ErrorType>, Never>.Output, URLError>')的 return 表达式转换为 return 类型 'AnyPublisher<Result<T, ErrorType>, Never>'错误。
您的实施中有几个主要流程。
首先,您不应该使用 Result
作为 Publisher
的 Output
类型和 Never
作为其 Failure
类型。您应该使用 T
作为 Output
和 ErrorType
作为 Failure
.
其次,你需要tryMap
和mapError
,而不是flatMap
。
最后,您处理 dataTaskPublisher
的结果完全错误。当 dataTaskPublisher
失败时,它会发出错误,因此您需要在 mapError
中处理它。当它成功时,它会以 data
的形式发出结果,因此您需要对其进行解码,而不是 response
.
func fetchData<T: Decodable>(url: URL) -> AnyPublisher<T, ErrorType> {
URLSession
.shared
.dataTaskPublisher(for: url)
.tryMap { data, _ in
return try JSONDecoder().decode(T.self, from: data)
}
.mapError { error -> ErrorType in
switch error {
case let urlError as URLError:
switch urlError.code {
case .notConnectedToInternet, .networkConnectionLost, .timedOut:
return .noInternetConnection
case .cannotDecodeRawData, .cannotDecodeContentData:
return .empty
default:
return .general
}
default:
return .general
}
}
.eraseToAnyPublisher()
}