错误'无效更新:尝试删除表中行的第0节中的无效行数

Mar*_*rty 15 objective-c uitableview ios

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

错误

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

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

完整来源

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

编辑

在Fennelouski发表评论后跟进,我是否应该沿着这些方向做点什么?

- (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];

    }
}
Run Code Online (Sandbox Code Playgroud)

编辑2

这就是我得到的:

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

Fen*_*ski 26

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

简短的回答是,您需要先从dataSource中删除一个项目,[ToDoItemSvc retrieveAllToDoItems]然后该项目会删除一行.

对此的补充是,当您添加一行时,您还需要向dataSource添加一个项目.

这些更改需要在您致电之前进行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];
}
Run Code Online (Sandbox Code Playgroud)

ELI5:一位老师有五个学生:Alice,Bob,Charlie,Diane和Eric.鲍勃的妈妈在午餐前从学校开始接他.午餐后,老师会出席和恐慌,因为他只有四个孩子,因为名单上应该有五个孩子.鲍勃在哪里?!

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