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

jvidinwx  于 2024-01-05  发布在  Swift
关注(0)|答案(2)|浏览(156)

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

  1. private func fetchAndProcessFeedsFinal(setSortOption: SortOption, page: Int?) -> Observable<Mutation> {
  2. if page != nil {
  3. resetPagination()
  4. } else if isLastPage {
  5. return .empty()
  6. } else {
  7. pages += 1
  8. }
  9. let nickname = "lemon""
  10. return feedRepository.findOtherFeed(request: FindOtherFeedRequest(nickname: nickname, date: requestDate, page: pages, size: 7))
  11. .flatMap { [weak self] (userFeeds, isLast) -> Observable<Mutation> in
  12. guard let self = self else { return .empty() }
  13. isLastPage = isLast
  14. if userFeeds.isEmpty { return Observable.just(.updateDataSource([])) }
  15. // MARK: inside processFeedWithProfileImage function it calls findProfileImg
  16. let observables: [Observable<UserFeedSection.Item>] = userFeeds.map {[weak self] feed in
  17. guard let self = self else { return Observable.just(.feed(FeedReactor(userFeed: feed, feedRepository: FeedRepository(), userRepository: UserRepository()))) }
  18. return processFeedWithProfileImage(feed)
  19. }
  20. let feedWithImage = userFeeds.flatMap { userFeed in
  21. userFeed.imageIdList.map { [weak self] imageId in
  22. return self?.feedRepository.findFeedImage(request: FindFeedImageRequest(imageId: imageId))
  23. }
  24. }
  25. return Observable.zip(observables)
  26. .map { items in
  27. return Mutation.updateDataSource(items)
  28. }
  29. }
  30. }

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

vsikbqxv

vsikbqxv1#

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

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

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

  1. enum Input {
  2. case receivePage(Int, [UserFeed])
  3. case addProfileImage(UserFeed, UIImage)
  4. case addFeedImage(String, UIImage)
  5. case getPage
  6. }
  7. struct CellDisplayable {
  8. let userFeed: UserFeed
  9. let profileImage: UIImage?
  10. let feedImages: [UIImage]
  11. }
  12. struct State {
  13. var pages: [Int: [UserFeed]] = [:]
  14. var profileImages: [UserFeed: UIImage] = [:]
  15. var feedImages: [String: UIImage] = [:]
  16. var items: [CellDisplayable] {
  17. pages.sorted { $0.key < $1.key }
  18. .flatMap { userFeeds in
  19. userFeeds.value.map {
  20. CellDisplayable(
  21. userFeed: $0,
  22. profileImage: profileImages[$0],
  23. feedImages: $0.imageIdList.compactMap { feedImages[$0] }
  24. )
  25. }
  26. }
  27. }
  28. }
  29. func example(api: API, tableView: UITableView) -> Observable<State> {
  30. cycle(
  31. input: tableView.rx.reachedBottom().startWith(()).map(to: Input.getPage),
  32. initialState: State(),
  33. reduce: { state, input in
  34. switch input {
  35. case let .receivePage(page, userFeeds):
  36. state.pages = [page: userFeeds]
  37. case let .addProfileImage(userFeed, image):
  38. state.profileImages[userFeed] = image
  39. case let .addFeedImage(imageId, image):
  40. state.feedImages[imageId] = image
  41. case .getPage:
  42. break
  43. }
  44. },
  45. reactions: [
  46. getProfileImages(api: api),
  47. getFeedImages(api: api),
  48. getPage(api: api)
  49. ]
  50. )
  51. }
  52. func getProfileImages(api: API) -> (Observable<(State, Input)>) -> Observable<Input> {
  53. { reaction in
  54. reaction
  55. .flatMap { userFeeds(from: $1) }
  56. .flatMap { userFeed in
  57. api.response(.findProfileImage(feed: userFeed))
  58. .map { (userFeed, $0) }
  59. }
  60. .map { Input.addProfileImage($0.0, $0.1) }
  61. }
  62. }
  63. func getFeedImages(api: API) -> (Observable<(State, Input)>) -> Observable<Input> {
  64. { reaction in
  65. reaction
  66. .flatMap { userFeeds(from: $1) }
  67. .flatMap { Observable.from($0.imageIdList) }
  68. .flatMap { imageId in
  69. api.response(.findFeedImage(imageId: imageId))
  70. .map { (imageId, $0) }
  71. }
  72. .map { Input.addFeedImage($0.0, $0.1) }
  73. }
  74. }
  75. func getPage(api: API) -> (Observable<(State, Input)>) -> Observable<Input> {
  76. { reaction in
  77. reaction
  78. .compactMap { neededPage(state: $0, input: $1) }
  79. .flatMap { page in
  80. api.response(.findOtherFeed(nickname: "lemon", date: Date(), page: page, size: 7))
  81. .map { (page, $0.0) }
  82. }
  83. .map { Input.receivePage($0.0, $0.1) }
  84. }
  85. }
  86. func userFeeds(from input: Input) -> Observable<UserFeed> {
  87. guard case let .receivePage(_, userFeeds) = input else { return .empty() }
  88. return .from(userFeeds)
  89. }
  90. func neededPage(state: State, input: Input) -> Int? {
  91. guard case .getPage = input else { return nil }
  92. return (state.pages.keys.max() ?? 0) + 1
  93. }

字符串

展开查看全部
oxalkeyp

oxalkeyp2#

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

  1. struct CellDisplayable {
  2. let userFeed: UserFeed
  3. var profileImage: UIImage?
  4. var feedImages: [UIImage?]
  5. }
  6. func example(api: API) -> Observable<[CellDisplayable]> {
  7. enum Input {
  8. case userFeeds([UserFeed])
  9. case profileImage(UserFeed, UIImage)
  10. case feedImage(String, UIImage)
  11. }
  12. let userFeeds = api.response(.findOtherFeed(nickname: "lemon", date: Date(), page: 1, size: 7))
  13. .share()
  14. let profileImages = userFeeds
  15. .flatMap { _, userFeeds in
  16. Observable.merge(userFeeds.map { userFeed in
  17. api.response(.findProfileImage(feed: userFeed))
  18. .map { (userFeed, $0) }
  19. })
  20. }
  21. let feedImages = userFeeds
  22. .flatMap { _, userFeeds in
  23. Observable.merge(
  24. userFeeds
  25. .flatMap { $0.imageIdList }
  26. .map { imageId in
  27. api.response(.findFeedImage(imageId: imageId))
  28. .map { (imageId, $0) }
  29. }
  30. )
  31. }
  32. return Observable<Input>.merge(
  33. userFeeds.map { Input.userFeeds($1) },
  34. profileImages.map { Input.profileImage($0.0, $0.1) },
  35. feedImages.map { Input.feedImage($0.0, $0.1) }
  36. )
  37. .scan(into: [CellDisplayable]()) { state, next in
  38. switch next {
  39. case let .userFeeds(userFeeds):
  40. state = userFeeds.map { CellDisplayable(userFeed: $0, profileImage: nil, feedImages: .init(repeating: nil, count: $0.imageIdList.count)) }
  41. case let .profileImage(userFeed, image):
  42. if let index = state.firstIndex(where: { $0.userFeed == userFeed }) {
  43. state[index].profileImage = image
  44. }
  45. case let .feedImage(imageId, image):
  46. if let index = state.firstIndex(where: { $0.userFeed.imageIdList.contains(imageId) }),
  47. let imageIndex = state[index].userFeed.imageIdList.firstIndex(of: imageId) {
  48. state[index].feedImages[imageIndex] = image
  49. }
  50. }
  51. }
  52. }

字符串

展开查看全部

相关问题