简体   繁体   English

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

[英]Deleting records in UITableViewController throws error

Problem: When I click the delete button for a given table/section row, i get the following error: "*** 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 (4) must be equal to the number of rows contained in that section before the update (4), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'" 问题:当我单击给定表/节行的删除按钮时,出现以下错误:“ ***由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的行数无效。更新(4)之后在现有节中包含的行数必须等于更新(4)之前在该节中包含的行数,加上或减去从该节插入或删除的行数(已插入0) ,其中1个已删除)。

在此处输入图片说明

From other posts I have read about this symptom, I gather I am suppose to be manually removing an element in my datasource array, but not sure how to access the section's array inside this method: 从我已阅读过的有关此症状的其他文章中,我收集到的信息是我想手动删除数据源数组中的一个元素,但不确定如何在此方法中访问该节的数组:

// 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
}   

} }

I think the complication for this situation arises due to the fact that the plist (FormEntries.plist) I am pulling data from holds user input for all sorts of things all through out my app, thus I am having to call and filter it for every section. 我认为这种情况的复杂性是由于以下事实而引起的:我正在从应用程序中拉出plist(FormEntries.plist)来保存用户输入的数据,因此我必须为每个应用程序进行调用和过滤部分。 This works fine to populate the UITableView and all of it's sections, but because a new filtered array is being created for and inside each section, I'm not sure how to ever access it again in order to remove the element, thus rectifying the above error message. 可以很好地填充UITableView及其所有部分,但是由于在每个部分内以及内部都创建了一个新的过滤数组,因此我不确定如何再次访问它以删除该元素,从而纠正了上述问题错误信息。 Here is how I am loading the data for each table section: 这是我为每个表部分加载数据的方式:

// 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;

} }

-- Not sure if this will help diagnose things, but here it is none the less --- -不确定这是否有助于诊断,但是在这里仍然如此-

// 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;    
}

What is the best approach to handle this situation or to resolve the above posted error message? 解决这种情况或解决上面发布的错误消息的最佳方法是什么?

-- UPDATE -- -更新-

So here is how I'm trying to identify which plist record to delete, assuming that's what I need to do to resolve the original error: 因此,这是我尝试确定要删除的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);
        }
    }
}

My logic here was to set a hidden unique identifier on tvc.detailTextLabel.text in the cellForRowAtIndexPath method, which in turn would let me know which record from the plist to filter and delete by calling [array removeObjectAtIndex:uid] where array is my filtered plist array. 我的逻辑是在cellForRowAtIndexPath方法中的tvc.detailTextLabel.text上设置一个隐藏的唯一标识符,这反过来又让我知道要过滤和删除plist中的哪个记录,方法是调用[array removeObjectAtIndex:uid],其中已过滤掉array plist数组。 Only problem now is that tvc in the NSLog always returns the record at index 0, not the row that holds the delete button I click. 现在唯一的问题是,NSLog中的tvc总是返回索引0处的记录,而不是包含我单击的删除按钮的行。

NSLog returns: tvc: < UITableViewCell: 0x713e2c0; NSLog返回:tvc:<UITableViewCell:0x713e2c0; frame = (0 30; 320 44); 框架=(0 30; 320 44); text = 'Church A'; 文字=“教堂A”; autoresize = W; autoresize = W; layer = < CALayer: 0x7113e70 > > - UID: -237206321 - g: 3 - count: 3. So why would tvc return the index 0 when it was index 3 I clicked the delete button? 层= <CALayer:0x7113e70>>-UID:-237206321-g:3-计数:3.那么为什么当tvc为索引3时,tvc返回索引0我单击了删除按钮?

Is this just becoming a clustered mess or is there a cleaner solution? 这仅仅是变成一团糟,还是有一个更清洁的解决方案? But ya, still stumped. 但是,你还是很困惑。

This error most definitely relates to your mishandling the data that you are trying to load to your table. 此错误肯定与您对要加载到表中的数据的处理不当有关。 I found that the easiest and safest way to handle modifying table content is to do something along those lines, with the necessary adjustments (within tableView:commitEditingStyle:) 我发现处理表内容修改的最简单,最安全的方法是根据需要进行一些调整(在tableView:commitEditingStyle:之内)

    //REMOVE A CELL FROM A SECTION 

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

In addition you need to make sure that your array is properly updated to have the changes reflected in the table. 另外,您需要确保正确更新了阵列以使更改反映在表中。

This is how I was finally able to resolve the issue: 这就是我最终能够解决此问题的方式:

I changed all of this crap: 我改变了所有这些废话:

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);
    }
  }
}

to one simple line: 简单的一行:

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

This allowed me to identify the cell I was working with. 这使我能够确定正在使用的单元。 So my final code that worked looks like this: 所以我最终的有效代码如下所示:

// 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];
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM