Reputation: 13283
I'm exploring Combine Swift with this project https://github.com/sgl0v/TMDB and I'm trying to replace its imageLoader with something that supports Combine: https://github.com/JanGorman/MapleBacon
The project has a function that returns the type AnyPublisher<UIImage?, Never>
.
But the imageLoader MapleBacon library returns the type AnyPublisher<UIImage, Error>
.
So I'm trying to convert types with this function:
func convert(_ loader: AnyPublisher<UIImage, Error>) -> AnyPublisher<UIImage?, Never> {
// here.
}
I actually found a question that is kinda similar to mine, but the answers weren't helpful: https://stackoverflow.com/a/58234908/3231194
What I've tried to so far (Matt's answer to the linked question).
The sample project has this function:
func loadImage(for movie: Movie, size: ImageSize) -> AnyPublisher<UIImage?, Never> {
return Deferred { return Just(movie.poster) }
.flatMap({ poster -> AnyPublisher<UIImage?, Never> in
guard let poster = movie.poster else { return .just(nil) }
let url = size.url.appendingPathComponent(poster)
let a = MapleBacon.shared.image(with: url)
.replaceError(with: UIImage(named: "")!) // <----
})
.subscribe(on: Scheduler.backgroundWorkScheduler)
.receive(on: Scheduler.mainScheduler)
.share()
.eraseToAnyPublisher()
}
if I do replaceError
,
I get the type Publishers.ReplaceError<AnyPublisher<UIImage, Error>>
BUT, I was able to solve this one, by extending the library.
extension MapleBacon {
public func image(with url: URL, imageTransformer: ImageTransforming? = nil) -> AnyPublisher<UIImage?, Never> {
Future { resolve in
self.image(with: url, imageTransformer: imageTransformer) { result in
switch result {
case .success(let image):
resolve(.success(image))
case .failure:
resolve(.success(UIImage(named: "")))
}
}
}
.eraseToAnyPublisher()
}
}
Upvotes: 1
Views: 3853
Reputation: 270790
First, you need to map
a UIImage
to a UIImage?
. The sensible way to do this is of course to wrap each element in an optional.
Then, you try to turn a publisher that sometimes produces errors to a publisher that Never
produces errors. You replaceError(with:)
an element of your choice. What element should you replace errors with? The natural answer, since your publisher now publishes optional images, is nil
! Of course, assertNoFailure
works syntactically too, but you might be downloading an image here, so errors are very likely to happen...
Finally, we need to turn this into an AnyPublisher
by doing eraseToAnyPublisher
MapleBacon.shared.image(with: url)
.map(Optional.some)
.replaceError(with: nil)
.eraseToAnyPublisher()
Upvotes: 7