使用ReactiveCocoa

时间:2015-07-27 17:57:15

标签: ios objective-c uitableview reactive-cocoa ios-animations

我有一个分页tableView,顶部有两个标签,最新和热门,我无法通过[tableView beginUpdates][tableView endUpdates]正确设置模型更改动画。

tableView有3种加载模式:

  • LoadingModeRefresh:用户刷新时刷新。
  • LoadingModeNewPage:当用户到达tableView的末尾以便需要加载新页面时
  • LoadingModeNewTab:当用户更改顶部的标签

我从后端每页收到30个项目(用于分页)

此外,我在tableView的末尾有一个加载单元格,这样当有人到达表的末尾时,他/她可以看到它正在加载,当新数据到达时,加载单元格是推到tableView的尽头,看不到。

我想要的行为如下:

  • 当用户进行刷新时,将提取30个新项目并将其设置为tableView的支持模型,tableView应将项目从0重新加载到29,并删除其余项目用户可能已经分页超过1页,因此在刷新之前可能有超过30个项目,因此我们需要在刷新后删除额外的项目。
  • 当用户到达表的末尾时,将获取30个新项目并将其附加到tableView的支持模型的末尾,我们应将这30行插入tableView
  • 当用户切换标签时,我首先要清除tableView所有单元格,以便我提到的加载单元格是唯一的单元格。所以我将tableView的支持模型设置为空数组,并从tableView中删除所有行。在获取30个新项目后,我将这30行插入tableView

我的ViewModel上有3个属性,表示对indexPaths的更改:indexPathsToDeleteindexPathsToInsertindexPathsToReload,这些属性绑定到支持模型中的更改{{1 }}。我的视图控制器观察这些属性,将它们拉到一起并立即应用更改。但不知怎的,我的提取代码被调用了两次,这导致indexPaths被多次计算和观察,这导致与-[RACSignal combinePrevious:reduce:]不一致并导致崩溃。任何人都可以帮助解决问题所在,因为我似乎无法理解发生了什么?

这里是tableView的代码(对不起代码,还没有重构它,因为我还没有让它工作):

ViewModel

以及在const NSInteger kArticlePerPage = 30; @interface FeedViewModel () @property (nonatomic, readwrite) Source *model; @property (nonatomic) LoadingMode loadingMode; @property (nonatomic) NSInteger selectedTabIndex; @property (nonatomic, readwrite) NSInteger pagesRequested; @property (nonatomic, readwrite) NSInteger pagesLoaded; @property (nonatomic, readwrite) NSArray *indexPathsToDelete; @property (nonatomic, readwrite) NSArray *indexPathsToInsert; @property (nonatomic, readwrite) NSArray *indexPathsToReload; - (NSArray *)indexPathsForRange:(NSRange)range inSection:(NSInteger)section; @end @implementation FeedViewModel - (instancetype)initWithModel:(Source *)source { self = [super init]; if (!self) { return nil; } _model = source; _pagesLoaded = 0; RACSignal *loadingModeSignal = RACObserve(self, loadingMode); RACSignal *newTabSignal = [loadingModeSignal // filter:^BOOL(NSNumber *loadingMode) { return loadingMode.integerValue == LoadingModeNewTab; }]; RACSignal *newPageSignal = [loadingModeSignal // filter:^BOOL(NSNumber *loadingMode) { return loadingMode.integerValue == LoadingModeNewPage; }]; RACSignal *refreshSignal = [loadingModeSignal // filter:^BOOL(NSNumber *loadingMode) { return loadingMode.integerValue == LoadingModeRefresh; }]; RAC(self, loading) = [loadingModeSignal // map:^id(NSNumber *loadingMode) { switch (loadingMode.integerValue) { case LoadingModeFinished: return @(NO); default: return @(YES); } }]; @weakify(self); RACSignal *newArticlesSignal = [[[[RACSignal combineLatest:@[ RACObserve(self, pagesRequested), RACObserve(self, selectedTabIndex) ]] sample:RACObserve(self, loadingMode)] // map:^id(RACTuple *tuple) { @strongify(self); return [self signalForNewArticlesForPage:tuple.first order:[tuple.second integerValue]]; }] // switchToLatest]; RACSignal *articlesForNewTabSignal = [[newTabSignal // flattenMap:^RACStream * (id value) { // return [newArticlesSignal startWith:@[]]; }] // skip:1]; RACSignal *articlesForNewPageSignal = [newPageSignal // flattenMap:^RACStream * (id value) { return [newArticlesSignal // map:^id(NSArray *newArticles) { @strongify(self); Article *article = self.articles[0]; NSLog(@"article name: %@", article.title); return [self.articles arrayByAddingObjectsFromArray:newArticles]; }]; }]; RACSignal *articlesForRefreshSignal = [refreshSignal // flattenMap:^RACStream * (id value) { // return newArticlesSignal; }]; RAC(self, articles) = [RACSignal merge:@[ articlesForNewTabSignal, // articlesForNewPageSignal, // articlesForRefreshSignal ]]; RACSignal *articlesSignal = RACObserve(self, articles); RAC(self, indexPathsToDelete) = [articlesSignal // combinePreviousWithStart:@[] // reduce:^id(NSArray *previous, NSArray *current) { @strongify(self); if (previous.count > current.count) { return [self indexPathsForRange:NSMakeRange(current.count, previous.count - current.count) inSection:0]; } else { return @[]; } }]; RAC(self, indexPathsToInsert) = [articlesSignal // combinePreviousWithStart:@[] // reduce:^id(NSArray *previous, NSArray *current) { // @strongify(self); if (previous.count < current.count) { return [self indexPathsForRange:NSMakeRange(previous.count, current.count - previous.count) inSection:0]; } else { return @[]; } }]; RAC(self, indexPathsToReload) = [articlesSignal // combinePreviousWithStart:@[] // reduce:^id(NSArray *previous, NSArray *current) { if (previous.count >= current.count) { return [self indexPathsForRange:NSMakeRange(0, current.count) inSection:0]; } else { return @[]; } }]; RAC(self, pagesLoaded) = [[RACObserve(self, articles) // skip:1] // map:^id(NSArray *array) { // NSInteger pages = array.count / kArticlePerPage; if (array.count % kArticlePerPage != 0) { pages++; } return @(pages); }]; RAC(self, separatorColorHexString) = [RACObserve(self, model.type) map:^id(NSNumber *type) { if (type.integerValue == SourceTypeInspiration) { return @"ffffff"; } else { return @"E5E5E5"; } }]; RAC(self, segmentTitles) = [RACObserve(self, model) // map:^id(Source *source) { NSMutableArray *titles = [NSMutableArray array]; if (source.isPopularAvailable) { [titles addObject:@"Popular"]; } if (source.isLatestAvailable) { [titles addObject:@"Latest"]; } return titles; }]; return self; } - (void)setCurrentSource:(Source *)source { self.model = source; } - (void)refreshCurrentTab { self.pagesRequested = 1; self.loadingMode = LoadingModeRefresh; } - (void)requestNewPage { if (self.pagesRequested == self.pagesLoaded + 1) { return; } self.pagesRequested = self.pagesLoaded + 1; self.loadingMode = LoadingModeNewPage; } - (void)selectTabWithIndex:(NSInteger)index { self.selectedTabIndex = index; self.pagesRequested = 1; self.loadingMode = LoadingModeNewTab; } - (void)selectTabWithIndexIfNotSelected:(NSInteger)index { if (self.selectedTabIndex == index) { return; } [self selectTabWithIndex:index]; } - (NSArray *)indexPathsForRange:(NSRange)range inSection:(NSInteger)section { NSMutableArray *indexes = [NSMutableArray array]; for (NSUInteger i = range.location; i < range.location + range.length; i++) { [indexes addObject:[NSIndexPath indexPathForRow:i inSection:section]]; } return [indexes copy]; } - (RACSignal *)signalForNewArticlesForPage:(NSNumber *)pageNumber order:(ArticleOrder)order { return [[SourceManager sharedManager] articlesForSourceKey:self.model.key articleOrder:order pageNumber:pageNumber]; } - (void)setLoadingMode:(LoadingMode)loadingMode { _loadingMode = loadingMode; } @end 中观察indexPath数组的代码:

ViewController.m

除此之外,我只在RACSignal *toDeleteSignal = [RACObserve(self, viewModel.indexPathsToDelete) // deliverOn:[RACScheduler mainThreadScheduler]]; // RACSignal *toInsertSignal = [RACObserve(self, viewModel.indexPathsToInsert) // deliverOn:[RACScheduler mainThreadScheduler]]; // RACSignal *toReloadSignal = [RACObserve(self, viewModel.indexPathsToReload) // deliverOn:[RACScheduler mainThreadScheduler]]; [[RACSignal zip:@[ toDeleteSignal, toInsertSignal, toReloadSignal ]] subscribeNext:^(RACTuple *tuple) { @strongify(self); [self.tableView beginUpdates]; [self.tableView deleteRowsAtIndexPaths:tuple.first withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView insertRowsAtIndexPaths:tuple.second withRowAnimation:UITableViewRowAnimationTop]; [self.tableView reloadRowsAtIndexPaths:tuple.third withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; if (self.tableView.pullToRefresh.state == BPRPullToRefreshStateLoading) { [self.tableView.pullToRefresh dismiss]; } }]; 为tableView中的最后一个单元调用[self.viewModel requestNewPage]时调用tableView:willDisplayCell:[self.viewModel selectTabWithIndexIfNotSelected:index]当段选择更改时。 viewDidLoad中的[self.viewModel selectTabWithIndex:0]和刷新处理程序中的[self.viewModel refreshCurrentTab]

我在哪里犯了错误?

0 个答案:

没有答案