UITableView崩溃后(显然)未能请求代表numberOfRowsInSection
当numberOfRowsInSection
返回的行数与数据源不一致时,这里有很多关于UITableViewController
s崩溃的问题。UITableView崩溃后(显然)未能请求代表numberOfRowsInSection
我的应用程序崩溃,因为这个问题 - 但我不明白为什么。为了增加混淆,它在真实的iPhone和iPhone模拟器上崩溃,但在(真正的)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的)崩溃的序列:
- 的TableView正常工作,一切都按预期执行,NSLog的消息以上定期弹出。
- 点击“添加新项目”按钮。
- 将新项目添加到JobStore(包含作业的NSArray的单例)。
- 打开一个模态导航控制器(UIModalPresentationFormSheet)来编辑该新项目。
- 取消编辑 - 并从JobStore中删除不需要的项目。
然后坠毁:
- 的TableView中更新本身,而无需调用numberOfRowsInSection(即,消息的NSLog以上没有出现),所以它试图从作为边界之外的作业存储检索对象的阵列。
我已经添加了的NSLog到对的视图控制器完成后执行被驳回dismissBlock:
[jobDetailViewController setDismissBlock:^{
NSLog(@"dismissBlock");
[[self tableView] reloadData];
[self clearTableViewBackgroundColorAndResetHighlight];
}];
当我选择“完成”并保存模态视图的项目这是执行,但不是当我选择'取消'时。代码行是在这两种方法是相同的,我知道,正确的方法正在呼吁每个按键:如果我简化dismissBlock
[[self presentingViewController] dismissViewControllerAnimated:YES completion: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?
我开始怀疑一些不同的模态视图的怪癖,但会感激任何帮助。提前致谢。
詹姆斯
UITableView
缓存值,以便它可以更有效的(这可能是每一个-depending你如何做你的计算时间问你潜在的慢)。
所以,如果你改变你的基础数据源,你需要让tableView
知道它。你可以做一个完整的[self.tableView reloadData];
或使用下列方法
– insertRowsAtIndexPaths:withRowAnimation:
– deleteRowsAtIndexPaths:withRowAnimation:
– moveRowAtIndexPath:toIndexPath:
– insertSections:withRowAnimation:
– deleteSections:withRowAnimation:
– moveSection:toSection:
这些通常内部调用用于
– beginUpdates
– endUpdates
检查docs
感谢您的快速答复。我使用了其中几种方法来处理in-tableView编辑(移动,删除) - 但是这个问题的编辑发生在单独的UIView中。那个UIView应该在完成时调用上面提到的'dismissBlock',并且应该调用'[[self tableView] reloadData]'让tableView知道更改......但是它似乎忽略了这个代码块案件。 – James 2013-04-05 14:32:49
你不能把这个逻辑放在'viewWillAppear:'而不是回调中吗?或者,您确定'done'和'cancel'遵循相同的代码路径吗? – 2013-04-05 14:36:41
好的 - 感谢您的答案提供的灵感解决问题!它需要我在将新对象添加到形成数据源的数组之前调用'[[self tableView] beginUpdates]',然后我必须将'[[self tableView] endUpdates]'添加到神秘的未调用代码块调用'[[self tableView] reloadData]'。突然它全部运行,并且代码块被执行编辑的UIVIew中的两条路由调用。我学习的书(Big Nerd Ranch iOS)没有提及'beginUpdates'或'endUpdates',所以我没有使用它们。现在我明白了。再次感谢。 – James 2013-04-05 14:40:57