我使用 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)
}
}
}
我尝试过 zip 和combineLatest,但我认为我没有以正确的方式使用它..
这是一个非常复杂的问题,特别是因为分页。您的示例中没有足够的信息来处理完整的询问。
这是我可能如何使用我的CLE 系统做这样的事情。
基本思路如下:
接下来的想法是遵循
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
}