0

UITableViewController当返回的行数numberOfRowsInSection与数据源不一致时,这里有很多关于 s 崩溃的问题。

由于这个问题,我的应用程序崩溃了——但我不明白为什么。更令人困惑的是,它在真正的 iPhone 和 iPhone Simulator 上崩溃,但在(真正的)iPad 上完美运行。

这是错误:

2013-04-05 14:38:15.644 JobTime[28484:c07] *** Terminating app due to uncaught
exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]:
index 3 beyond bounds [0 .. 2]'

没错——NSArray 只扩展到 2。

奇怪的是,TableView 在刷新之前似乎没有向我的控制器(设置为它的委托)询问该部分中的行数。这是我的方法:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"called numberOfRowsInSection");
    return [[[JobStore sharedStore] allJobs] count];
}

这是 iPhone 模拟器(但不是 iPad)上崩溃的顺序:

  1. TableView 工作正常,一切正常,上面的 NSLog 消息定期弹出。
  2. 单击“添加新项目”按钮。
  3. 将新项目添加到 JobStore(包含作业 NSArray 的单例)。
  4. 打开一个模式 navigationController (UIModalPresentationFormSheet) 以编辑该新项目。
  5. 取消编辑 - 并从 JobStore 中删除不需要的项目。

然后崩溃:

  1. TableView 在不调用 numberOfRowsInSection 的情况下自行更新(即没有出现上面的 NSLog 消息),因此它尝试从 JobStore 中检索数组边界之外的对象。

我已将 NSLog 添加到在 ViewController 被关闭时执行的dismissBlock:

[jobDetailViewController setDismissBlock:^{
    NSLog(@"dismissBlock");
    [[self tableView] reloadData];
    [self clearTableViewBackgroundColorAndResetHighlight];
}];

当我选择“完成”并从模式视图中保存项目时执行,但当我选择“取消”时不会执行。两种方法的代码行相同,我知道每个按钮都调用了正确的方法:

[[self presentingViewController] dismissViewControllerAnimated:YES completion:dismissBlock];

如果我将dismissBlock 简化为仅一个NSLog 语句而没有其他调用,情况也是如此:在“取消”情况下不会调用它。

我发现的唯一解决方案是在 cellForRowAtIndexPath 中重新检查数组的边界相当不雅:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
                                  reuseIdentifier:@"UITableViewCell"];
    }

    // Check array bounds before trying to retrieve object from array

    if ([indexPath row] < [self tableView:tableView numberOfRowsInSection:0]) {
        Job *j = [[[JobStore sharedStore] allJobs] objectAtIndex:[indexPath row]];
        [[cell textLabel] setText:[j displayDescription]];
        [[cell detailTextLabel] setText:[j timeDescription]];

        if ([j selected]) {
            [cell setBackgroundColor:[UIColor lightGrayColor]];
        }
    } else {
        [[cell textLabel] setText:@""];
        NSLog(@"gone past array bounds");
    }
    return cell;
}

这行得通,但它很笨拙。知道为什么 TableView 在刷新之前似乎不要求更新的行数吗?或者为什么它可以在 iPad 上运行,而在 iPhone 上不行?

我开始怀疑不同模式视图的一些怪癖,但如果有任何帮助,我将不胜感激。提前致谢。

詹姆士

4

1 回答 1

0

UITableView缓存值以便提高效率(每次询问您可能会很慢 - 取决于您如何进行计算)。

因此,如果您更改底层数据源,则需要tableView告知它。您可以做一个完整的[self.tableView reloadData];或使用以下方法

– insertRowsAtIndexPaths:withRowAnimation:
– deleteRowsAtIndexPaths:withRowAnimation:
– moveRowAtIndexPath:toIndexPath:
– insertSections:withRowAnimation:
– deleteSections:withRowAnimation:
– moveSection:toSection:

这些通常在调用内部使用

– 开始更新
–结束更新

检查文档

于 2013-04-05T14:24:12.380 回答