1

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() } } 
6
  • @JoakimDanielson IDK, just a challenge, like the whole sample project has that type. I too want an optional UIImage versus an UIImage with Error publisher in a ViewModel (just like in the sample project). Commented Apr 13, 2021 at 9:42
  • That seems like a perfect duplicate target. How didn't those answers solve your problem? Commented Apr 13, 2021 at 9:53
  • @DávidPásztor See the comment in the answer to the linked question. I actually tried it, but it seems it's just getting more complicated for me. One solution that I'm looking at now is to just extend the library. Commented Apr 13, 2021 at 10:03
  • 1
    Can you show what you have tried from that post? What has "got more complicated"? Matt's answer should do the job. Commented Apr 13, 2021 at 10:10
  • Thanks @Sweeper. See my edit. I added my current solution too. Commented Apr 13, 2021 at 10:42

1 Answer 1

7

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() 
Sign up to request clarification or add additional context in comments.

1 Comment

Also, I appreciate the explanation!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.