【问题标题】:Delete a Row from UITableView causes Crash从 UITableView 中删除一行会导致崩溃
【发布时间】:2012-10-15 22:59:40
【问题描述】:

以下情况:我想从我的 UITableView 中删除一行,但这总是崩溃...

@property (nonatomic,retain) NSMutableArray *daten;

@synthesize daten;

然后在我的 viewDidLoad 中填充我的数组:

-(NSMutableArray *) daten{
if (!daten) {
    self.daten = [[NSMutableArray alloc] init];
}

@try {
    NSFileManager *fileMgr = [NSFileManager defaultManager];
    NSString *dbPath = [self getDBPath];
    BOOL success = [fileMgr fileExistsAtPath:dbPath];
    if(!success)
    {
        NSLog(@"Cannot locate database file '%@'.", dbPath);
    }
    if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
    {
        NSLog(@"An error has occured: %s", sqlite3_errmsg(db));

    }


    const char *sql = "SELECT * FROM  Daten";
    if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
    {
        NSLog(@"Problem with prepare statement:  %s", sqlite3_errmsg(db));
    }else{

        while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
            Daten * infos = [[Daten alloc] init];
            infos.download = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,1)];
            infos.upload = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
            infos.ping = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,3)];
            infos.comment = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,4)];
            infos.date = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,5)];
            infos.type = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,6)];
            infos.lati = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,7)];
            infos.longi = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,8)];


            [daten addObject:infos];
        }
    }
}
@catch (NSException *exception) {
    NSLog(@"Problem with prepare statement:  %s", sqlite3_errmsg(db));
}
@finally {
    sqlite3_finalize(sqlStatement);
    sqlite3_close(db);

    return daten;
}
}

如果我想删除一行:

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

if (editingStyle == UITableViewCellEditingStyleDelete) {
    // Delete the row from the data source
    //[self.daten removeAllObjects];
    NSString *selectedCategory = [self.daten objectAtIndex:indexPath.row];
    NSLog(@"there are %d objects in the array", [self.daten count]);
    [self.daten removeObjectAtIndex:indexPath.row]; //we assume, that mySourceArray is a NSMutableArray we use as our data source
    NSLog(@"there are %d objects in the array", [self.daten count]);

    [self.tableView beginUpdates];

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

    [self.tableView endUpdates];

....}

它崩溃了,因为我的数组计数在删除之前和之后都是一样的!但我不知道为什么...

我的 NumberOfRowsInSection:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.
return [self.daten count];


}

这是一个例外:

2012-10-15 16:45:13.778 Speedcheck[5297:907] *** Assertion failure in -[UITableView         _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2372/UITableView.m:1070

2012-10-15 16:45:13.779 Speedcheck[5297:907] * 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (26) 必须等于更新前该节中包含的行数 (26),加上或减去从该节中插入或删除的行数(0 插入,1 删除) 加上或减去移入或移出该部分的行数(0 移入,0 移出)。 * 首先抛出调用栈: (0x3adcf3e7 0x35934963 0x3adcf29d 0x390c67b3 0x36569ba1 0x82311 0x366fefe1 0x3662003f 0x3661fff3 0x3661ffcd 0x3661f883 0x3662003f 0x3661fff3 0x3661ffcd 0x3661f883 0x3661fd71 0x365485c1 0x365358a9 0x365351b7 0x3ac025f7 0x3ac02227 0x3ada43e7 0x3ada438b 0x3ada320f 0x3ad1623d 0x3ad160c9 0x3ac0133b 0x36589289 0x51d33 0x34984b20) libc++abi.dylib:终止调用抛出异常

【问题讨论】:

  • 您介意发布您的- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 方法吗?
  • 也发布错误消息,您可能需要更新模型以反映已删除的行
  • 快速想法(不确定是否是这样):尝试将 [self.daten removeObjectAtIndex:indexPath.row]; 放入 beginUpdates/endUpdates 块中,以便 numberOfRowsInSection 在之前/之后返回不同的值。
  • 试过了,还是一样的例外!
  • 那个方法还有更多代码吗?

标签: iphone objective-c


【解决方案1】:

您的-(NSMutableArray *) daten 方法似乎有问题。

看起来你想进行惰性初始化,但实际上,每当调用此方法时,都会再次重构数组。因此,您的删除仅在下次访问数组之前有效,此时数组再次被填满(甚至看起来它应该不断增长)。

你可能想要类似的东西

-(NSMutableArray *) daten{
   if (daten)
      return daten;

   self.daten = [[NSMutableArray alloc] init];

   // ... same setup as before

}

改为。

【讨论】:

  • 我们可以使用 self.在吸气剂方法中?它不会进入循环吗?抱歉,如果我的概念有误。
  • 设置没有问题,因为它调用[set setDaten: ...]。在从 getter 调用 getter 或从 setter 调用 setter 时,您只需要小心无限循环。
  • 他也合成了属性。在我的一个项目中,我实现了自定义 setter 和 getter,但我没有使用 synthesize。他的情况是否正确?
  • 是的,只是你没有实现的方法会被合成。
  • 哇,你绝对让我开心...太愚蠢了,我没明白...谢谢
【解决方案2】:

我不知道它是否有帮助,因为这对我来说没有意义,但是将[self.daten removeObjectAtIndex:indexPath.row]; 放在对[self.tableView beginUpdates]; 的调用之后并将结果报告给我们!

【讨论】:

  • 不,对不起,和以前一样的异常!
【解决方案3】:

从 UITableView 中删除单元格的最简单方法是从数据数组中删除对象。

只需执行以下操作:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // If row is deleted, remove it from the list.
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        NSInteger rowNumber = indexPath.row;

        [self.daten removeObjectAtIndex:rowNumber];

        [tableView reloadData];
    }
}

【讨论】:

  • 那是尽可能的低效。
  • 好吧,那不是我。但是重新加载整个表是一个坏习惯,它并没有解决这里的主要问题。
【解决方案4】:

你几乎拥有它。您真正想做的就是在检查编辑样式后立即输入这一行:

if (editingStyle == UITableViewCellEditingStyleDelete) {

[self.tableView beginUpdates];

这是因为您希望模型更改发生在 beginUpdates 块中,否则会出现不一致。

【讨论】: