出于科学原因,我创建了一个Publisher和订户这样我就可以进入Combine了
已经转换从一个从不失败失败一。
enum IntegerError: String, Error {
case miltupleOf2 = "We are sorry but the number is a multiple of 2, therefore cannot be used in the process"
}
let integerPublisher = [1,3,3,3,3,3,5,6,7,7].publisher
.setFailureType(to: IntegerError.self)
let subscribtion = integerPublisher
.tryMap { intValue in
if intValue.isMultiple(of: 2) {
throw IntegerError.miltupleOf2
} else {
return intValue
}
}
.sink { completion in
switch completion {
case .finished:
print("success")
case .failure(let error):
if let error = error as? IntegerError {
print(error.rawValue)
} else {
print(error)
}
}
} receiveValue: { value in
print(value)
}
我的问题是:当使用sink时,错误类型为error. 为什么不自定义IntegerError.setFailureType修饰符?
将错误类型强制转换为前面指定的类型似乎有点多余。
谢谢。
原因很简单。tryMap
返回一个Publishers.TryMap<Upstream, Output>
,这是一个特定类型的发布者,Failure == Error
:
typealias Failure = Error
所以只要你使用tryMap
,setFailureType
所做的就会撤销。
Publishers.TryMap
将Error
作为其Failure
类型的原因是因为在Swift中,你不能指定闭包可以抛出的特定类型的错误(不像Java)。一旦将闭包标记为throws
,就像tryMap
对其transform
参数所做的那样:
func tryMap<T>(_ transform: @escaping (Self.Output) throws -> T) -> Publishers.TryMap<Self, T>
任何Error
都可以在transform
闭包中抛出。您可以尝试更改throw IntegerError.miltupleOf2
以抛出另一种类型的错误。你的代码仍然可以编译。
假设,如果Swift允许你指定在闭包中允许抛出的错误类型,那么tryMap
可以被声明为(假语法):
func tryMap<T, E: Error>(_ transform: @escaping (Self.Output) throws E -> T) -> Publishers.TryMap<Self, T, E>
,你甚至不需要setFailureType
。
作为一种解决方法,您可以使用mapError
将错误转换为所需的类型:
let subscribtion = integerPublisher
.tryMap { intValue -> Int in
if intValue.isMultiple(of: 2) {
throw IntegerError.miltupleOf2
} else {
return intValue
}
}.mapError { $0 as! IntegerError }
.sink { completion in
switch completion {
case .finished:
print("success")
case .failure(let error):
print(error.rawValue)
}
} receiveValue: { value in
print(value)
}
您需要向编译器保证您没有在tryMap
中抛出任何其他类型的错误。