我有一个分页tableView
,顶部有两个标签,最新和热门,我无法通过[tableView beginUpdates]
和[tableView endUpdates]
正确设置模型更改动画。
tableView
有3种加载模式:
LoadingModeRefresh
:用户刷新时刷新。LoadingModeNewPage
:当用户到达tableView
的末尾以便需要加载新页面时LoadingModeNewTab
:当用户更改顶部的标签我从后端每页收到30个项目(用于分页)
此外,我在tableView
的末尾有一个加载单元格,这样当有人到达表的末尾时,他/她可以看到它正在加载,当新数据到达时,加载单元格是推到tableView
的尽头,看不到。
我想要的行为如下:
tableView
的支持模型,tableView
应将项目从0重新加载到29,并删除其余项目用户可能已经分页超过1页,因此在刷新之前可能有超过30个项目,因此我们需要在刷新后删除额外的项目。 tableView
的支持模型的末尾,我们应将这30行插入tableView
tableView
所有单元格,以便我提到的加载单元格是唯一的单元格。所以我将tableView
的支持模型设置为空数组,并从tableView
中删除所有行。在获取30个新项目后,我将这30行插入tableView
。我的ViewModel
上有3个属性,表示对indexPaths的更改:indexPathsToDelete
,indexPathsToInsert
和indexPathsToReload
,这些属性绑定到支持模型中的更改{{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]
。
我在哪里犯了错误?