今回やりたかったこと
UITableViewで以下を実施。
- データが0件の場合は、セルを1つ表示し「なし」と表示
- データが1件以上の場合は、データの数だけセルを表示
- 上記の条件で、アニメーションでいいかんじに削除できるようにする
問題
- 2→1件はOKだが、1→0の削除をした場合に下記エラーで落ちる
エラーメッセージ
error
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
ソースコード(誤)
SampleTableView.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger cnt = [self.items count];
return (0 == cnt)? cnt+1 : cnt;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self beginUpdates];
[self.items removeObject:self.items[indexPath.row]];
[self deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self endUpdates];
原因
- deleteRowsAtIndexPaths:で1→0件にするアニメーションを呼んでいるが、numberOfRowsInSection:で返す値は常に1のため、不整合が生じて落ちる。
解法方
- 1→0件の場合のみ、deleteRowsAtIndexPaths:withRowAnimation: ではなく reloadRowsAtIndexPaths:withRowAnimation:を呼べばOK.
ソースコード(正)
SampleTableView.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger cnt = [self.items count];
return (0 == cnt)? cnt+1 : cnt;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self beginUpdates];
[self.items removeObject:self.items[indexPath.row]];
if (indexPath.row < [self tableView:self numberOfRowsInSection:indexPath.section]) {
[self reloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
} else {
[self deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
[self endUpdates];
これでOK.
あとはアニメーションを諦めて[self reloadData]を呼んでしまえば問題はないが、今回はアニメーションさせたかったのでこうしました。
もっといい方法や気になる点があれば、気軽にコメントください。