2

我有一个tableView顶部有 2 个选项卡的分页,最新和流行,我无法使用[tableView beginUpdates]和正确地为模型更改设置动画[tableView endUpdates]

有 3 种加载模式tableView

  • LoadingModeRefresh:当用户使用拉动刷新时。
  • LoadingModeNewPage:当用户到达末尾时tableView需要加载新页面
  • LoadingModeNewTab:当用户更改顶部的选项卡时

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

另外我在末尾有一个加载单元,tableView这样当有人到达表格的末尾时,他/她可以看到它正在加载,当新数据到达时,加载单元被推到末尾tableView,出视线。

我想要的行为如下:

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

我有 3 个属性ViewModel代表对 indexPaths 的更改:和indexPathsToDelete,它们与. 我的视图控制器观察这些属性,将它们压缩在一起并立即应用更改。但是不知何故,我的获取代码被调用了两次,这导致 indexPaths 被计算和观察不止一次,这导致与 不一致并导致崩溃。任何人都可以帮助解决问题所在,因为我似乎无法理解发生了什么?indexPathsToInsertindexPathsToReload-[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]时调用。在 viewDidLoad 和刷新处理程序中。tableView:willDisplayCell:[self.viewModel selectTabWithIndexIfNotSelected:index][self.viewModel selectTabWithIndex:0][self.viewModel refreshCurrentTab]

我在哪里犯错?

4

0 回答 0