Если инициализатор URL(string:)
не работает (возвращает nil
), вы должны решить, в какую ошибку вы хотите это исправить. Допустим, вы хотите превратить его в URLError
. Итак, если URL(string:)
возвращает nil
, создайте URLError
и используйте Fail
издателя, чтобы опубликовать sh it:
func jsonContents<T: Decodable>(
ofUrl urlString: String,
as type: T.Type,
decodedBy decoder: JSONDecoder = JSONDecoder()
) -> AnyPublisher<T, Error> {
guard let url = URL(string: urlString) else {
let error = URLError(.badURL, userInfo: [NSURLErrorKey: urlString])
return Fail(error: error).eraseToAnyPublisher()
}
return URLSession.shared
.dataTaskPublisher(for: url)
.tryMap { result -> T in
return try decoder.decode(T.self, from: result.data)
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
Но если вы действительно хотите добавить больше, объедините его , вы можете использовать Result.Publisher
вместо Fail
:
func jsonContents<T: Decodable>(
ofUrl urlString: String,
as type: T.Type,
decodedBy decoder: JSONDecoder = JSONDecoder()
) -> AnyPublisher<T, Error> {
return (
URL(string: urlString)
.map { Result.success($0) } // This is Optional.map
?? Result.failure(URLError(.badURL, userInfo: [NSURLErrorKey: urlString]))
)
.publisher
.flatMap({
URLSession.shared
.dataTaskPublisher(for: $0)
.tryMap { result -> T in
return try decoder.decode(T.self, from: result.data)
}
})
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
Но вещи трудно читать. Мы можем выделить использование Result
в новом операторе, unwrapOrFail(with:)
:
extension Publisher {
func unwrapOrFail<Wrapped>(with error: Failure) -> Publishers.FlatMap<Result<Wrapped, Self.Failure>.Publisher, Self> where Output == Wrapped? {
return self
.flatMap ({
$0
.map { Result.success($0).publisher }
?? Result.failure(error).publisher
})
}
}
И затем использовать его следующим образом:
func jsonContents<T: Decodable>(
ofUrl urlString: String,
as type: T.Type,
decodedBy decoder: JSONDecoder = JSONDecoder()
) -> AnyPublisher<T, Error> {
return Result.success(urlString).publisher
.map { URL(string: $0) }
.unwrapOrFail(with: URLError(.badURL, userInfo: [NSURLErrorKey: urlString]))
.flatMap({
URLSession.shared
.dataTaskPublisher(for: $0)
.tryMap { result -> T in
return try decoder.decode(T.self, from: result.data)
}
})
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
Обратите внимание, что если по пути вы совершите любую ошибку, вы, вероятно, получите непостижимое сообщение об ошибке, и вам придется разбирать свой длинный конвейер, чтобы Swift мог сказать вам, что на самом деле не так.