如何使用RxSwift发送初始数据,然后与新的合并结合?

jvidinwx  于 5个月前  发布在  Swift
关注(0)|答案(2)|浏览(53)

我使用3个api来获取tableview的数据。首先,feedRepository.findOtherFeed返回包含数据数组和Bool的元组的Observable。对于数据数组中的每个元素,我调用userRepository.findProfileImg来获取每个数据的配置文件图像。每个数据都有一个名为userFeed.imageIdList的属性,对于每个id,我调用feedRepository.findFeedImage来获取数据的图像。
这些数据将显示在tableView中。我想尽快向用户显示,这意味着我不能等待所有数据的imageIdList调用feedRepository.findFeedImage。每当userRepository.findProfileImg完成时,我想首先向用户显示我所得到的,然后当feedRepository.findFeedImage完成时,我想更新数据。
我不是很流利地使用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() }
    
                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)
                    }
                
            
            }
    }

字符串
我试过压缩和组合最新的,但我认为我没有使用它的正确方法..

vsikbqxv

vsikbqxv1#

这是一个相当复杂的问题,特别是因为分页。您的示例中没有足够的信息来处理完整的问题。
下面是我如何使用我的CLE system来做类似的事情。
其基本思想如下:

  • 每当表视图到达底部时,尝试获取UserFeeds的页面。从第一个页面的初始请求开始。
  • 每当一个页面的UserFeeds进来,要求所有的个人资料图像。
  • 同样,当一个UserFeeds页面进来时,请求所有的feedImages。
  • 每当一个配置文件图像进来,将其存储在状态中。
  • 每当一个feedImage进来时,将其存储在状态中。

然后,我们的想法是遵循example(api:tableView:)函数的输出。每当有页面或图像进入时,状态就会更新。它的items数组将包含迄今为止下载的所有UserFeed以及CellDisplayable对象中每个userFeed对象的所有图像。

enum Input {
    case receivePage(Int, [UserFeed])
    case addProfileImage(UserFeed, UIImage)
    case addFeedImage(String, UIImage)
    case getPage
}

struct CellDisplayable {
    let userFeed: UserFeed
    let profileImage: UIImage?
    let feedImages: [UIImage]
}

struct State {
    var pages: [Int: [UserFeed]] = [:]
    var profileImages: [UserFeed: UIImage] = [:]
    var feedImages: [String: UIImage] = [:]
    var items: [CellDisplayable] {
        pages.sorted { $0.key < $1.key }
            .flatMap { userFeeds in
                userFeeds.value.map {
                    CellDisplayable(
                        userFeed: $0,
                        profileImage: profileImages[$0],
                        feedImages: $0.imageIdList.compactMap { feedImages[$0] }
                    )
                }
            }
    }
}

func example(api: API, tableView: UITableView) -> Observable<State> {
    cycle(
        input: tableView.rx.reachedBottom().startWith(()).map(to: Input.getPage),
        initialState: State(),
        reduce: { state, input in
            switch input {
            case let .receivePage(page, userFeeds):
                state.pages = [page: userFeeds]
            case let .addProfileImage(userFeed, image):
                state.profileImages[userFeed] = image
            case let .addFeedImage(imageId, image):
                state.feedImages[imageId] = image
            case .getPage:
                break
            }
        },
        reactions: [
            getProfileImages(api: api),
            getFeedImages(api: api),
            getPage(api: api)
        ]
    )
}

func getProfileImages(api: API) -> (Observable<(State, Input)>) -> Observable<Input> {
    { reaction in
        reaction
            .flatMap { userFeeds(from: $1) }
            .flatMap { userFeed in
                api.response(.findProfileImage(feed: userFeed))
                    .map { (userFeed, $0) }
            }
            .map { Input.addProfileImage($0.0, $0.1) }
    }
}

func getFeedImages(api: API) -> (Observable<(State, Input)>) -> Observable<Input> {
    { reaction in
        reaction
            .flatMap { userFeeds(from: $1) }
            .flatMap { Observable.from($0.imageIdList) }
            .flatMap { imageId in
                api.response(.findFeedImage(imageId: imageId))
                    .map { (imageId, $0) }
            }
            .map { Input.addFeedImage($0.0, $0.1) }
    }
}

func getPage(api: API) -> (Observable<(State, Input)>) -> Observable<Input> {
    { reaction in
        reaction
            .compactMap { neededPage(state: $0, input: $1) }
            .flatMap { page in
                api.response(.findOtherFeed(nickname: "lemon", date: Date(), page: page, size: 7))
                    .map { (page, $0.0) }
            }
            .map { Input.receivePage($0.0, $0.1) }
    }
}

func userFeeds(from input: Input) -> Observable<UserFeed> {
    guard case let .receivePage(_, userFeeds) = input else { return .empty() }
    return .from(userFeeds)
}

func neededPage(state: State, input: Input) -> Int? {
    guard case .getPage = input else { return nil }
    return (state.pages.keys.max() ?? 0) + 1
}

字符串

oxalkeyp

oxalkeyp2#

这是一个不需要反馈系统的答案,但它只能下拉一个页面。你必须更新它才能下拉其他页面。
这个想法的关键是merge的使用(你不想使用zipcombineLatest)。在每个网络请求完成后,Observable结果将发出一个数组,包含到目前为止为所讨论的页面检索到的所有信息。

struct CellDisplayable {
    let userFeed: UserFeed
    var profileImage: UIImage?
    var feedImages: [UIImage?]
}

func example(api: API) -> Observable<[CellDisplayable]> {
    enum Input {
        case userFeeds([UserFeed])
        case profileImage(UserFeed, UIImage)
        case feedImage(String, UIImage)
    }

    let userFeeds = api.response(.findOtherFeed(nickname: "lemon", date: Date(), page: 1, size: 7))
        .share()

    let profileImages = userFeeds
        .flatMap { _, userFeeds in
            Observable.merge(userFeeds.map { userFeed in
                api.response(.findProfileImage(feed: userFeed))
                    .map { (userFeed, $0) }
            })
        }

    let feedImages = userFeeds
        .flatMap { _, userFeeds in
            Observable.merge(
                userFeeds
                    .flatMap { $0.imageIdList }
                    .map { imageId in
                        api.response(.findFeedImage(imageId: imageId))
                            .map { (imageId, $0) }
                    }
            )
        }

    return Observable<Input>.merge(
        userFeeds.map { Input.userFeeds($1) },
        profileImages.map { Input.profileImage($0.0, $0.1) },
        feedImages.map { Input.feedImage($0.0, $0.1) }
    )
        .scan(into: [CellDisplayable]()) { state, next in
            switch next {
            case let .userFeeds(userFeeds):
                state = userFeeds.map { CellDisplayable(userFeed: $0, profileImage: nil, feedImages: .init(repeating: nil, count: $0.imageIdList.count)) }
            case let .profileImage(userFeed, image):
                if let index = state.firstIndex(where: { $0.userFeed == userFeed }) {
                    state[index].profileImage = image
                }
            case let .feedImage(imageId, image):
                if let index = state.firstIndex(where: { $0.userFeed.imageIdList.contains(imageId) }),
                   let imageIndex = state[index].userFeed.imageIdList.firstIndex(of: imageId) {
                    state[index].feedImages[imageIndex] = image
                }
            }
        }
}

字符串

相关问题