删除UITableViewController中的记录会引发错误

时间:2011-08-26 21:58:09

标签: iphone objective-c uitableview

问题:当我单击给定表/节行的删除按钮时,我收到以下错误:“***因未捕获的异常而终止应用程序'NSInternalInconsistencyException',原因:'无效更新:无效的行数更新后的现有部分中包含的行数(4)必须等于更新前该部分中包含的行数(4),加上或减去从该部分插入或删除的行数(0已插入,1已删除)。'“

enter image description here

我从其他帖子中读到过有关此症状的内容,我收集到这里我想手动删除数据源数组中的元素,但不知道如何在此方法中访问该节的数组:

// COMMIT EDITING STYLE
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"indexPath: %@", indexPath);    

if (editingStyle == UITableViewCellEditingStyleDelete) {
    // Delete the row from the data source        
   [tableView beginUpdates];
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [tableView endUpdates]; // throws error here
    [tableView reloadData];   
}   
else if (editingStyle == UITableViewCellEditingStyleInsert) {
    // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}   

}

我认为这种情况的复杂性是由于plist(FormEntries.plist)我从我的应用程序中提取所有类型的东西来保存用户输入的数据,因此我不得不调用和过滤它适用于每个部分。这可以很好地填充UITableView及其所有部分,但因为正在为每个部分创建一个新的过滤数组,我不知道如何再次访问它以删除元素,从而纠正上述错误信息。以下是我为每个表部分加载数据的方法:

// CELL FOR ROW AT INDEXPATH
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";    
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}

NSNumber *numScreenId = [[arrayOfModulesScreens objectAtIndex: indexPath.section] objectForKey: @"id"];
NSMutableArray *arrayRecords = [epFrameWork selectPlist: @"FormEntries" filterByKey: @"screen_id" keyValue:numScreenId];

NSString *strTitle = [[arrayRecords objectAtIndex: indexPath.row] objectForKey: @"storage_string"];

cell.textLabel.text = strTitle;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;           
return cell;

}

- 不确定这是否有助于诊断事情,但这里确实如此---

// TITLE FOR HEADER IN SECTION
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[arrayOfModulesScreens objectAtIndex: section] objectForKey: @"screen_title"];
}

// NUMBER OF SECTIONS IN TABLE VIEW 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrayOfModulesScreens count];
}


// NUMBER OF ROWS IN SECTION
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSNumber *numScreenId = [[arrayOfModulesScreens objectAtIndex: section] objectForKey: @"id"];
NSMutableArray *arrayRecords = [epFrameWork selectPlist: @"FormEntries" filterByKey: @"screen_id" keyValue:numScreenId];
int rowCount = [arrayRecords count];
return rowCount;    
}

处理这种情况或解决上述错误消息的最佳方法是什么?

- 更新 -

所以这就是我如何确定删除哪个plist记录,假设我需要做的就是解决原始错误:

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

int g = indexPath.row;
int count = -1;
UITableViewCell *tvc = [[UITableViewCell alloc] init];
for(id element in tableView.subviews) {
    if([element isKindOfClass:[UITableViewCell class]]) {
       count +=1; 
        NSLog(@"g: %d - count: %d", g , count);
        if(count == g) {
            tvc = element;
            NSLog(@"tvc: %@ - UID: %@ - g: %d - count: %d", tvc, tvc.detailTextLabel.text, g , count);
        }
    }
}

我的逻辑是在cellForRowAtIndexPath方法的tvc.detailTextLabel.text上设置一个隐藏的唯一标识符,这反过来会让我知道plist中的哪条记录通过调用[array removeObjectAtIndex:uid]来过滤和删除其中的数组是我过滤的plist数组。现在唯一的问题是NSLog中的tvc总是返回索引0处的记录,而不是保存我单击的删除按钮的行。

NSLog返回:tvc:< UITableViewCell:0x713e2c0; frame =(0 30; 320 44); text ='教堂A'; autoresize = W; layer =< CALayer:0x7113e70> > - UID:-237206321 - g:3 - count:3。那么为什么tvc在索引3时返回索引0我点击了删除按钮?

这只是一团糟或是否有更清洁的解决方案?但是,你还是难过。

2 个答案:

答案 0 :(得分:0)

此错误肯定与您错误处理要加载到表中的数据有关。我发现处理修改表内容的最简单,最安全的方法是沿着这些行做一些事情,并进行必要的调整(在tableView:commitEditingStyle中)

    //REMOVE A CELL FROM A SECTION 

    [yourTable beginUpdates];
    [yourTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
    [yourTable endUpdates];
    [yourTable reloadData];

此外,您需要确保正确更新阵列以使更改反映在表格中。

答案 1 :(得分:0)

这就是我最终能够解决问题的方法:

我改变了所有这些废话:

int g = indexPath.row;
int count = -1;
UITableViewCell *tvc = [[UITableViewCell alloc] init];
for(id element in tableView.subviews) {
if([element isKindOfClass:[UITableViewCell class]]) {
   count +=1; 
    NSLog(@"g: %d - count: %d", g , count);
    if(count == g) {
        tvc = element;
        NSLog(@"tvc: %@ - UID: %@ - g: %d - count: %d", tvc, tvc.detailTextLabel.text, g , count);
    }
  }
}

到一个简单的界限:

UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath];   

这使我能够识别出我正在使用的细胞。所以我的最终代码看起来像这样:

// COMMIT EDITING STYLE
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{

if (editingStyle == UITableViewCellEditingStyleDelete) {
    UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath];        
    [epFrameWork deleteRecordFromPlist:@"FormEntries" uid:cell.detailTextLabel.text];        
    [tableView reloadData];         

}   
else if (editingStyle == UITableViewCellEditingStyleInsert) {
    // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
 }   
}

-(void) deleteRecordFromPlist:(NSString *)plist uid:(NSString *)uId {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *tmpFileName = [[NSString alloc] initWithFormat:@"%@.plist", plist];
NSString *path = [documentsDirectory stringByAppendingPathComponent:tmpFileName];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSDictionary *dict = [[NSDictionary alloc] init];
NSString *tmpUid;
for(int i=0; i < [array count]; i++) {
    dict = [array objectAtIndex:i];
    tmpUid = [dict valueForKey:@"uid"];
    if([tmpUid isEqualToString:uId]) {
       [array removeObjectAtIndex:i];
       [array writeToFile:path atomically:YES];
    }
  }
}