刷新表格时应用程序崩溃(可能是tableView上的调用endUpdates导致崩溃)

Posted

技术标签:

【中文标题】刷新表格时应用程序崩溃(可能是tableView上的调用endUpdates导致崩溃)【英文标题】:App crashes when refreshing table (Probably the call endUpdates on tableView causes the crash) 【发布时间】:2013-03-24 12:17:24 【问题描述】:

看到这篇文章,但没有解决我的问题。

iPhone app crashing on [self.tableView endUpdates]

拥有来自报纸网站的UITableView loads 文章。首先load 作品 正如预期的那样,但是当我再次使用UIRefreshControlfetch 文章时,我的应用程序崩溃了 当 (animating) inserting rows.

错误:

代码:

- (void)insertRowsWithAnimation

    NSMutableArray *indexPaths = [NSMutableArray array];
    NSInteger i = self.latestArticlesArray.count - self.latestArticlesArray.count;

    for (NSDictionary *dict in self.latestArticlesArray) 
        [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
        i++;
    
    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
    [self.tableView endUpdates];


- (void)fetchEntries

    UIView *currentTitleView = [[self navigationItem] titleView];
    UIActivityIndicatorView *aiView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];

    [[self navigationItem] setTitleView:aiView];
    [aiView startAnimating];

    void (^completionBlock) (NSArray *array, NSError *err) = ^(NSArray *array, NSError *err) 
        if (!err) 
            [[self navigationItem] setTitleView:currentTitleView];
            self.latestArticlesArray = [NSArray array];
            self.latestArticlesArray = array;
            [self insertRowsWithAnimation];
        
    ;
    [[Store sharedStore] fetchArticlesWithCompletion:completionBlock];


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    return self.latestArticlesArray.count;

如果您想查看更多方法,请告诉我。希望你能帮忙。从我到目前为止所了解到的情况来看,我认为帖子的数量已经改变,因此该表期望显示其他数量的文章?

【问题讨论】:

发布你的 numberOfRowsInSection: 方法。错误通常是因为您调用了 insertRow 但没有更改此方法中返回的行数 看我的帖子,我只是回馈count,我是否必须在这个method中以某种方式刷新latesArticlesArray 【参考方案1】:

线

NSInteger i = self.latestArticlesArray.count - self.latestArticlesArray.count;

i 设置为,因此insertRowsAtIndexPaths 使用空数组调用。

我假设您的意图是使用新添加行的行号调用insertRowsAtIndexPaths,但是在替换数组之前您必须记住旧数据

self.latestArticlesArray = array;

但请注意,由于您替换了整个数组,因此您也可以调用

[self.tableView reloadData];

而不是beginUpdates/insertRowsAtIndexPaths/endUpdates


更新:我的第一个分析是错误的(而 wattson12 的分析是正确的)。正如您在 cmets 中所说,您只需要一个简单的动画即可删除所有先前的行并在获取后插入新行。可以这样做:

- (void)replaceArticlesWithAnimation:(NSArray *)articles

    NSUInteger oldCount = [self.latestArticlesArray count];
    self.latestArticlesArray = articles;
    NSUInteger newCount = [self.latestArticlesArray count];

    [self.tableView beginUpdates];
    for (NSUInteger i = 0; i < oldCount; i++) 
        [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
    
    for (NSUInteger i = 0; i < newCount; i++) 
        [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
    
    [self.tableView endUpdates];

fetchEntries你打电话

if (!err) 
    [[self navigationItem] setTitleView:currentTitleView];
    [self replaceArticlesWithAnimation:array];

【讨论】:

调用reloadData 会杀死inserting rows 的整个动画。我知道将NSInteger 设置为 0 看起来很奇怪,但出于某种原因它可以工作。正如我在原始帖子中提到的,第一次加载有效,我看到rows 被插入animated way,但当我再次调用method 时却没有。还有其他想法吗? @McClane:我现在看到我没有正确分析您的代码,我认为 wattson12 是正确的。 @McClane:要获得完美的动画更新,您必须比较新旧数组,删除文章时调用deleteRowsAtIndexPaths,新文章时调用insertRowsAtIndexPaths @McClane:如果第一次获取加载文章 A、B、C、D、E,然后获取文章 C、D、E、F、G,那么您将调用 deleteRowsAtIndexPaths 获取行0 和 1,insertRowsAtIndexPaths 用于第 3、4 行,以获得正确的动画。 首先感谢您帮助我。我重新加载文章并不复杂(还)。我只是加载最新的 100 篇文章。没有 A B C 文章,我只想显示最新的 100 篇文章,所以我得到的响应始终是 100 个对象(最新的)。我没有提到任何发布日期或类似的东西。【参考方案2】:

它第一次加载的原因是因为你每次都插入一些行,所以在第一次运行时,行数从 0 变为数组中的计数(在完成块中),你调用 insertRows索引路径的数量等于数组的计数。

第二次调用它是在插入新行,但没有更新计数以反映新的总和。您应该将现有数组添加到完成块中返回的数组中,并在 numberOfRowsInSection 中返回该组合数组的计数

【讨论】:

我确实将从block 返回的array 分配给我在method numberOfRowsInSection 中使用的array。见callfetchEntriesblock:self.latestArticlesArray = array; @McClane:如果您使用 5 个行号调用 insertRowsAtIndexPaths,那么表格视图会假定表格有 5 行比以前多 @Martin,我很困惑,为什么是 5?我只是将更新后的self.latestArticlesArraycompletion block 提供给插入行的方法。但这具体是如何工作的呢?该方法只是尝试/想要插入新数据还是只是重新添加所有数据? @McClane:假设第一次 fetch 将 3 个对象加载到 self.latestArticlesArray。然后下一次 fetch 加载 5 个对象。您替换数组,这样self.latestArticlesArray 现在包含5 个对象。然后你用 5 行调用 insertRowsAtIndexPaths,因此表格视图假定表格有 3 + 5 = 8 个对象。 @Martin,我对报纸 API 的 call 是有限的,每当我 call fetchEntries 时,限制设置为 100 篇文章,所以我总是得到 100 objects。所以实际上我不能有不同数量的objects 和几个fetchEntries calls【参考方案3】:
dispatch_async(dispatch_get_main_queue(), ^(void)
        //Run UI Updates
    );

【讨论】:

将 [self.tableView endUpdates] 放入 dispach_async 块中。这会异步更新主队列中的 UI。使用它解决了我的问题。希望对你有用。

以上是关于刷新表格时应用程序崩溃(可能是tableView上的调用endUpdates导致崩溃)的主要内容,如果未能解决你的问题,请参考以下文章

使用致命错误刷新tableview时应用程序崩溃:索引超出范围Swift3

刷新 Tableview 控制器时 UIRefreshControl 崩溃

快速在表格视图中插入新行时应用程序崩溃?

通过从上到下滚动表格来刷新 UITable 内容

高效刷新 TableView?

重新加载数据时 Tableview 崩溃