Swift 合并转换发布者类型

Swift combine Convert Publisher type

我正在探索 Combine Swift 与这个项目 https://github.com/sgl0v/TMDB 我正在尝试用支持 Combine 的东西替换它的 imageLoader:https://github.com/JanGorman/MapleBacon

该项目具有 returns 类型 AnyPublisher<UIImage?, Never> 的功能。 但是 imageLoader MapleBacon 库 returns 类型 AnyPublisher<UIImage, Error>.

所以我正在尝试使用此函数转换类型:

func convert(_ loader: AnyPublisher<UIImage, Error>) -> AnyPublisher<UIImage?, Never> {
    // here.
}

我实际上发现了一个与我的有点相似的问题,但答案没有帮助:


到目前为止我已经尝试过什么(Matt 对相关问题的回答)。

示例项目有这个功能:

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()
    }

如果我这样做 replaceError,

我得到类型 Publishers.ReplaceError<AnyPublisher<UIImage, Error>>


但是,我能够通过扩展库来解决这个问题。

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()
    }
}

首先,你需要map一个UIImage到一个UIImage?。明智的做法当然是将每个元素包装在一个可选的。

然后,您尝试将有时会产生错误的发布者转变为 Never 会产生错误的发布者。你 replaceError(with:) 一个你选择的元素。您应该用什么元素替换错误?自然的答案是 nil,因为您的发布商现在发布了 可选 张图片!当然,assertNoFailure在句法上也是可行的,但是你可能在这里下载图片,所以很可能会发生错误...

最后,我们需要通过 eraseToAnyPublisher

将其变成 AnyPublisher
MapleBacon.shared.image(with: url)
    .map(Optional.some)
    .replaceError(with: nil)
    .eraseToAnyPublisher()