尝试删除表中的行时出现错误“无效的更新:第0部分中的行数无效" [英] Error 'Invalid update: invalid number of rows in section 0' attempting to delete row in table

查看:108
本文介绍了尝试删除表中的行时出现错误“无效的更新:第0部分中的行数无效"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码似乎运行得很好,但是当我滑动以删除UITableView中的一行时,应用程序崩溃,并显示以下内容:

My code appears to run just fine but when I swipe to delete a line within my UITableView, the app crashes with the following:

LittleToDoApp [70390:4116002] ***由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的行数无效.更新后现有节中包含的行数(1 )必须等于更新(1)之前该节中包含的行数,加上或减去从该节中插入或删除的行数(插入0,删除1),再加上或减去移入的行数或从该部分移出(移入0,移出0).'

LittleToDoApp[70390:4116002] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

ViewController.m

#import "ViewController.h"
#import "ToDoItem.h"
#import "ToDoItemSvcCache.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize tableView;

ToDoItemSvcCache *ToDoItemSvc = nil;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    ToDoItemSvc = [[ToDoItemSvcCache alloc] init];
}



- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)deleteToDoItem:(id)sender {
    NSLog(@"Deleting ToDoItem");

    [self.view endEditing:YES];

}

- (IBAction)addToDoItem:(id)sender {

    [self.view endEditing:YES];

    NSLog(@"saveToDoItem: entering");
    ToDoItem *todoitem = [[ToDoItem alloc] init];
    todoitem.todoitem = _toDoItem.text;
    [ToDoItemSvc createToDoItem:todoitem];

    [self.tableView reloadData];
    NSLog(@"saveToDoItem: todoitem saved");

}


- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *simpleTableIdentifier = @"toDoItemCell";
    UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:simpleTableIdentifier];
    }
    ToDoItem *toDoItem = [[ToDoItemSvc retrieveAllToDoItems]
                    objectAtIndex:indexPath.row];
    cell.textLabel.text = [toDoItem description];
    return cell;
}



- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
    return [[ToDoItemSvc retrieveAllToDoItems] count];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}



- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"viewToDoItem"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        SecondViewController *destViewController = segue.destinationViewController;
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
        destViewController.toDoItemName = cell.textLabel.text;
    }
}

#pragma hiding status bar

- (BOOL)prefersStatusBarHidden {
    return YES;
}

// here we get back from both styles
- (IBAction)unwindFromDetailViewController:(UIStoryboardSegue *)segue
{
    // UIViewController *detailViewController = [segue sourceViewController];
    NSLog(@"%@", segue.identifier);
}

//Allows the delete button to show up when left swipping a list item

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return YES - we will be able to delete all rows
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Will add code to actually delete a row here. Adding NSLog so we know its triggering though
    NSLog(@"Deleted row.");

    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

    [self.tableView reloadData];

}

@end

ToDoItemSvc.h

#import <Foundation/Foundation.h>
#import "ToDoItem.h"

@protocol ToDoItemSvc <NSObject>

    - (ToDoItem *) createToDoItem: (ToDoItem *) todoitem;
    - (NSMutableArray *) retrieveAllToDoItems;
    - (ToDoItem *) updateToDoItem: (ToDoItem *) todoitem;
    - (ToDoItem *) deleteToDoItem: (ToDoItem *) todoitem;

@end

完整源代码

https://github.com/martylavender/LittleToDoApp/tree/Storyboards

在听完Fennelouski的评论之后,我是否应该遵循这些原则?

Following up after the comment/s made by Fennelouski, should I have something along these lines?

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [self.toDoItem removeObjectAtIndex:indexPath.row];

        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
        [self.tableView reloadData];

    }
}

编辑2

这就是我得到的:

Edit 2

This is what I am getting:

https://www.evernote.com/l/AJiah58lVhdGXIYO1F5yv6fJXc7k3WjRLNYB/image. >

https://www.evernote.com/l/AJiah58lVhdGXIYO1F5yv6fJXc7k3WjRLNYB/image.png

推荐答案

表中的行数为[[ToDoItemSvc retrieveAllToDoItems] count].当您删除表中的1行时,表中的行数应小于删除任何行之前的行数.删除1行并调用[self.tableView reloadData]后,tableView将检查以查看表中有多少行.此时,numberOfRowsInSection将返回[[ToDoItemSvc retrieveAllToDoItems] count].现在,该值应该比删除行之前的值小1.

The number of rows in your table is [[ToDoItemSvc retrieveAllToDoItems] count]. When you delete 1 row in your table, then the number of rows in your table should be 1 less than the number of rows before deleting any rows. After you delete 1 row and call [self.tableView reloadData] the tableView checks to see how many rows there are in the table. At this point, numberOfRowsInSection will return [[ToDoItemSvc retrieveAllToDoItems] count]. This should now be 1 less than it was before you deleted a row.

简单的答案是,您需要首先从数据源中删除一个看起来是[ToDoItemSvc retrieveAllToDoItems]的项目,然后删除一行.

The short answer is, you need to first remove an item from your dataSource, which appears to be [ToDoItemSvc retrieveAllToDoItems] then delete a row.

对此的称赞是,当您添加一行时,您还需要向dataSource中添加一个项.

The compliment to this is when you add a row, you need to add an item to your dataSource as well.

这些更改需要在致电reloadData之前进行.

These changes need to happen before you call reloadData.

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    // Actually remove the data from the source
    [ToDoItemSvc deleteToDoItem:[ToDoItemSvc retrieveAllToDoItems][indexPath.row]]

    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

    [self.tableView reloadData];
}

ELI5:一位老师有五个学生:爱丽丝(Alice),鲍勃(Bob),查理(Charlie),黛安(Diane)和埃里克(Eric).鲍勃的妈妈在午餐前从学校提早接他.午餐后,老师上课和惊慌,因为清单上说应该有五个孩子,他只有四个孩子.鲍勃在哪里?

ELI5: A teacher has five students: Alice, Bob, Charlie, Diane, and Eric. Bob's mom picks him up early from school before lunch. After lunch, the teacher takes attendance and panics because he only has four kids when the list says there should be five. Where's Bob?!

如果鲍勃的妈妈在带他离开学校时从名单上删除了他的名字,那么老师就不会惊慌.

If Bob's mom had removed his name from the list when she took him out of school then the teacher wouldn't have panicked.

这篇关于尝试删除表中的行时出现错误“无效的更新:第0部分中的行数无效"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆