Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/114.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用ReactiveCocoa在分页UITableView中设置行添加/重新加载/删除动画_Ios_Objective C_Uitableview_Reactive Cocoa_Ios Animations - Fatal编程技术网

Ios 使用ReactiveCocoa在分页UITableView中设置行添加/重新加载/删除动画

Ios 使用ReactiveCocoa在分页UITableView中设置行添加/重新加载/删除动画,ios,objective-c,uitableview,reactive-cocoa,ios-animations,Ios,Objective C,Uitableview,Reactive Cocoa,Ios Animations,我有一个分页的表格视图,顶部有两个选项卡,分别是最新的和流行的,我无法使用[tableView beginUpdates]和[tableView endUpdates]来正确设置模型更改的动画 表视图有3种加载模式: 加载ModereFresh:当用户使用pull刷新时 LoadingModeNewPage:当用户到达表格视图的末尾时,需要加载新页面 加载模式新选项卡:当用户更改顶部的选项卡时 我从后端每页收到30个项目(用于分页) 另外,我在tableView的末尾有一个加载单元格,这样当

我有一个分页的
表格视图
,顶部有两个选项卡,分别是最新的和流行的,我无法使用
[tableView beginUpdates]
[tableView endUpdates]
来正确设置模型更改的动画

表视图有3种加载模式

  • 加载ModereFresh
    :当用户使用pull刷新时
  • LoadingModeNewPage
    :当用户到达
    表格视图的末尾时,需要加载新页面
  • 加载模式新选项卡
    :当用户更改顶部的选项卡时
我从后端每页收到30个项目(用于分页)

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

我想要的行为如下:

  • 当用户拉取刷新时,将获取30个新项目,并将其设置为
    tableView
    的支持模型,
    tableView
    应将项目从0重新加载到29,并删除其余项目,因为用户可能翻页超过1页,因此刷新前可能有30多个项目,因此,我们需要在刷新后删除额外的项
  • 当用户到达表的末尾时,将获取30个新项,并将其附加到
    tableView
    的支持模型的末尾,我们应该将这30行插入
    tableView
  • 当用户切换选项卡时,我首先希望清除
    tableView
    中的所有单元格,以便我提到的加载单元格是唯一的单元格。因此,我将
    tableView
    的备份模型设置为空数组,并从
    tableView
    中删除所有行。取回30个新项目后,我将这30行插入
    表视图
我的
ViewModel
上有3个属性,表示对indexPaths的更改:
indexPathsToDelete
indexPathsToInsert
indexPathsToReload
,这些属性与支持模型中的更改绑定在一起,使用
-[RACSignal combinePrevious:reduce:
。我的视图控制器观察这些属性,将它们拉到一起并立即应用更改。然而,不知何故,我的获取代码被调用了两次,这导致indexpath被计算和观察了不止一次,这导致与
tableView
不一致,并导致崩溃。既然我似乎不明白发生了什么事,谁能帮我解决问题呢

以下是
ViewModel
的代码(很抱歉,代码还没有重构,因为我还没有让它工作):

除此之外,我只在为表视图中的最后一个单元格调用
[self.viewModel requestNewPage]
时调用
[self.viewModel selectTabWithIndexIfNotSelected:index]
段选择更改时调用
[self.viewModel selectTabWithIndexIfNotSelected:index]
<代码>[self.viewModel selectTabWithIndex:0]
在viewDidLoad中,在刷新处理程序中
[self.viewModel refreshCurrentTab]

我哪里出错了

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
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];
        }

    }];