RxSwift: задержка наблюдаемой до завершения другой наблюдаемой? - PullRequest
0 голосов
/ 01 февраля 2019

Я загружаю сообщения с сервера и хочу показать их только , когда их изображения все загружены .Вот что я пытался сделать:

postsRepository
    .fetchPosts()
    .flatMap { posts -> Observable<[Post]> in
        return Observable.merge(posts.map({ /* Code that returns Observable<UIImage> */ }))
            .takeLast(1)
            .map { _ in posts }
    }

Однако этот код выше загружает изображения дважды: как только все сообщения извлечены, и как только я привяжу сообщения к представлению таблицы.Как с этим бороться?

1 Ответ

0 голосов
/ 02 февраля 2019

Это было забавно ...

let postsWithImages = postsRepository
    .fetchPosts()
    .flatMap { posts in
        Observable.combineLatest(
            posts
                .map { $0.imageURL }
                .map { URLSession.shared.rx.data(request: URLRequest(url: $0))
                    .map { UIImage(data: $0) }
                    .catchErrorJustReturn(nil)
                }
            )
            .map { zip(posts, $0) }
    }
    .map { $0.map { (post: $0.0, image: $0.1) } }

Это последнее map может не быть строго необходимым, если вам удобно работать с Zip2Sequence.

. Вышепредполагается, что Post обладает свойством imageURL: URL.


Давайте немного очистим это:

let postsWithImages = postsRepository
    .fetchPosts()
    .flatMap { posts in
        Observable.combineLatest(
            posts
                .map { $0.imageURL }
                .map { URLSession.shared.rx.image(for: $0) }
            )
            .map { zip(posts, $0) }
    }
    .map { $0.map { (post: $0.0, image: $0.1) } }

Выше требуется новая функция:

extension Reactive where Base == URLSession {
    func image(for url: URL) -> Observable<UIImage?> {
        return data(request: URLRequest(url: url))
            .map { UIImage(data: $0) }
            .catchErrorJustReturn(nil)
    }
}

Я подумал, что хотел бы добавить некоторые объяснения.Как я уже упоминал в своей статье Рецепты для объединения наблюдаемых в RxSwift , магия здесь заключается в использовании combineLatest для преобразования [Observable<T>] в Observable<[T]>.

Операторберет массив Observables, подписывается на все из них, ожидает их завершения, а затем генерирует событие с массивом всех собранных значений.(После этого он будет генерировать новый массив каждый раз, когда обновляется один из элементов, но здесь это не актуально.)

...