You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用RxSwift先输出带头像的Feed数据,再合并图片数据更新?

问题描述

我需要通过三个API为TableView获取数据,流程如下:

  • 首先调用feedRepository.findOtherFeed,返回包含数据数组和Bool值的Tuple类型Observable;
  • 接着为数据数组中的每个元素调用userRepository.findProfileImg获取头像;
  • 每个数据的userFeed.imageIdList属性中的每个ID,需调用feedRepository.findFeedImage获取对应图片。

展示需求:无需等待所有Feed图片加载完成,只要头像加载完成就先显示内容,待所有Feed图片加载完成后再更新数据。

我对RxSwift不太熟练,尝试过zip和combineLatest但用法有误,当前代码如下:

private func fetchAndProcessFeedsFinal(setSortOption: SortOption, page: Int?) -> Observable<Mutation> {
    
    if page != nil {
        resetPagination()
    } else if isLastPage {
        return .empty()
    } else {
        pages += 1
    }
    
    let nickname = "lemon"

    return feedRepository.findOtherFeed(request: FindOtherFeedRequest(nickname: nickname, date: requestDate, page: pages, size: 7)) 
        .flatMap { [weak self] (userFeeds, isLast) -> Observable<Mutation> in
            guard let self = self else { return .empty() }

            isLastPage = isLast

            if userFeeds.isEmpty { return Observable.just(.updateDataSource([])) }
            
            // MARK: inside processFeedWithProfileImage function it calls findProfileImg 
            let observables: [Observable<UserFeedSection.Item>] = userFeeds.map {[weak self] feed in
                guard let self = self else { return Observable.just(.feed(FeedReactor(userFeed: feed, feedRepository: FeedRepository(), userRepository: UserRepository()))) }

                return processFeedWithProfileImage(feed)
            } 
            
          
            let feedWithImage = userFeeds.flatMap { userFeed in
                userFeed.imageIdList.map { [weak self] imageId in
                    return self?.feedRepository.findFeedImage(request: FindFeedImageRequest(imageId: imageId))
                }
            }
          
            return Observable.zip(observables)
                .map { items in
                    return Mutation.updateDataSource(items)
                }
            
        }
}

寻求正确的实现方案。


解决方案

核心思路是拆分两个阶段的数据流:先完成头像加载并发送初始数据更新,再完成所有Feed图片加载后发送最终数据更新,用RxSwift的流组合操作符实现分步推送。

具体实现代码

private func fetchAndProcessFeedsFinal(setSortOption: SortOption, page: Int?) -> Observable<Mutation> {
    
    if page != nil {
        resetPagination()
    } else if isLastPage {
        return .empty()
    } else {
        pages += 1
    }
    
    let nickname = "lemon"

    return feedRepository.findOtherFeed(request: FindOtherFeedRequest(nickname: nickname, date: requestDate, page: pages, size: 7))
        .flatMap { [weak self] (userFeeds, isLast) -> Observable<Mutation> in
            guard let self = self else { return .empty() }
            
            self.isLastPage = isLast
            
            if userFeeds.isEmpty {
                return .just(.updateDataSource([]))
            }
            
            // 1. 第一阶段:加载所有头像,生成初始Item(无Feed图片)
            let initialItemsObservable = Observable.zip(
                userFeeds.map { self.processFeedWithProfileImage($0) }
            )
            .map { items -> Mutation in
                .updateDataSource(items)
            }
            
            // 2. 第二阶段:为每个Feed加载所有图片,更新对应Item
            let updatedItemsObservable = Observable.zip(
                userFeeds.enumerated().map { index, feed in
                    // 先获取已加载头像的初始Item
                    self.processFeedWithProfileImage(feed)
                        .flatMap { initialItem -> Observable<UserFeedSection.Item> in
                            // 加载当前Feed的所有图片
                            let imageObservables = feed.imageIdList.map { imageId in
                                self.feedRepository.findFeedImage(request: FindFeedImageRequest(imageId: imageId))
                            }
                            
                            return Observable.zip(imageObservables)
                                .map { images -> UserFeedSection.Item in
                                    // 根据初始Item和加载的图片,生成更新后的Item
                                    switch initialItem {
                                    case .feed(let reactor):
                                        // 假设FeedReactor有更新图片的方法或属性
                                        let updatedReactor = FeedReactor(
                                            userFeed: reactor.userFeed,
                                            feedRepository: reactor.feedRepository,
                                            userRepository: reactor.userRepository
                                        )
                                        updatedReactor.feedImages = images // 替换为实际更新逻辑
                                        return .feed(updatedReactor)
                                    default:
                                        return initialItem
                                    }
                                }
                        }
                }
            )
            .map { updatedItems -> Mutation in
                .updateDataSource(updatedItems)
            }
            
            // 3. 组合两个阶段:先推送初始数据,再推送更新后的数据
            return initialItemsObservable.concat(updatedItemsObservable)
        }
}

关键逻辑说明

  • 第一阶段:用zip等待所有头像加载完成,生成带头像的初始Item,立即发送updateDataSource事件,让TableView先显示带头像的内容。
  • 第二阶段:对每个Feed,先拿到已加载头像的初始Item,再加载该Feed的所有图片,完成后更新Item的图片信息;最后用zip等待所有Feed的图片都加载完成,发送最终的updateDataSource事件。
  • 流组合:使用concat保证初始数据更新先触发,之后再触发图片加载完成后的更新,符合"先显示、后更新"的需求。

注意事项

  • 确保processFeedWithProfileImage返回的Observable<UserFeedSection.Item>已经正确注入了头像数据。
  • 根据你的FeedReactor实际结构调整图片更新的逻辑(示例中用feedImages属性替换,需改成你项目中的实际实现)。
  • 若需要支持图片加载过程中逐张更新(而非等待所有图片加载完再更新),可以把第二阶段的zip换成merge,并针对单个Item发送局部更新事件(比如新增Mutation.updateItem(at:index, with:item)类型)。

内容的提问来源于stack exchange,提问作者Sue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 06:34:59