LoginSignup
26
29

More than 5 years have passed since last update.

UITableView の deleteRowsAtIndexPaths: で落ちる場合の対処法

Last updated at Posted at 2014-02-21

今回やりたかったこと

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]を呼んでしまえば問題はないが、今回はアニメーションさせたかったのでこうしました。

もっといい方法や気になる点があれば、気軽にコメントください。

26
29
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
29