删除行:错误'无效更新:第0部分中的行数无效'

时间:2013-10-30 09:34:56

标签: ios iphone objective-c uitableview core-data

2013年11月24日:我做了一些调试,我发现removeProject工作正常。 (我在删除之前和之后都打印了所有项目)只有当它返回时 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)部分计数为0而不是(total - 1)。

============

我暂时停留在这个错误上一段时间了。为了更好地理解核心数据,我创建了这个测试项目,您可以在其中输入客户端和他的项目。这些项目与客户有关。 对于项目,我复制了客户端的ViewController并进行了一些小的更改。 我可以输入多个客户端然后删除它们。当我想删除相关项目时,问题就出现了。如果客户端只有一个项目,我可以删除它而不会出现任何错误。如果客户有两个或更多项目,我无法从该客户端删除任何项目。 删除会给我这个错误:

2013-10-30 10:00:23.145 [6160:70b] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2903.2/UITableView.m:1330
2013-10-30 10:00:23.147 [6160:70b] *** 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 (0) must be equal to the number of rows contained in that section before the update (2), 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).'
*** First throw call stack:
(

 .....
     )
     libc++abi.dylib: terminating with uncaught exception of type NSException
     Program ended with exit code: 0 

在这个网站上阅读了很多答案后,我的猜测是我需要更改我的代码      numberOfRowsInSection方法,但我看不到要改变的地方。

我的代码:

我创建了一个数据存储区:

DataStore.m

    #import "BITDataStore.h"
    #import "Client.h"
    #import "Project.h"

    @implementation DataStore


+ (BITDataStore *)sharedStore
{
    static BITDataStore *sharedStore = nil;
    if (!sharedStore) 
        sharedStore = [[super allocWithZone:nil]init];

        return sharedStore;
}    

-(void)removeClient:(Client *)client
{
    // remove from NSManagedObjectContext
    [context deleteObject:client];

    // remove from allClients array
    [allClients removeObjectIdenticalTo:client];
    NSLog(@"remove client");
}

-(void)removeProject:(Project *)project
{
    // remove from NSManagedObjectContext
    [context deleteObject:project];

    // remove from allProjects array
    [allProjects removeObjectIdenticalTo:project];

    // remove from relatedProjects array 
    [relatedProjects removeObjectIdenticalTo:project];
    NSLog(@"remove project %@", [project project]);

}


-(NSArray *)relatedProjects:(Client *)client;
{
    NSFetchRequest *request = [[NSFetchRequest alloc]init];

    NSEntityDescription *e = [[model entitiesByName] objectForKey:@"Project"];

    [request setEntity:e];

    // Check if client is related to Project
    [request setPredicate: [NSPredicate predicateWithFormat:@"clients == %@", client.objectID]];

    NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"project"
                                                         ascending:YES];
    [request setSortDescriptors:[NSArray arrayWithObject:sd]];

    NSError *error;
    NSArray *result = [context executeFetchRequest:request error:&error];

    if (!result) {
        [NSException raise:@"Fetch failed"
                    format:@"Reason: %@", [error localizedDescription]];
    }
    relatedProjects = [[NSMutableArray alloc] initWithArray:result];

    return relatedProjects;
}   
@end

ProjectDataViewController.m

@synthesize client, project;


-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [[self tableView] reloadData];
}


#pragma mark - Table view data source

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[[BITDataStore sharedStore]relatedProjects:client]count];        
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Configure the cell...
    if (cell == nil){
        cell = [[UITableViewCell alloc]
                initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
    }

   Project *p = [[[BITDataStore sharedStore]relatedProjects:client]
                                              objectAtIndex:[indexPath row]];

    [[cell textLabel] setText:[p project]];

    return cell;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        BITDataStore *ds = [BITDataStore sharedStore];
        NSArray *selectedProjects = [ds relatedProjects:client];

        Project *pr = [selectedProjects objectAtIndex:[indexPath row]];
        NSLog(@"Deleting project %@", [pr project]);
       [ds removeProject:pr];

        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        // Finally, reload data in view
        [[self tableView] reloadData];
        NSLog(@"Reload data"); 
    }   
    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
    }   
}

@end

希望这是足够的信息,如果没有,请告诉我。

2 个答案:

答案 0 :(得分:2)

将我的删除规则从cascade更改为nullify并且它有效。

答案 1 :(得分:0)

虽然您需要阅读更多代码以确定,但从您的描述中可以看出问题在于删除元素时表视图的更新不正确。

  

为了更好地理解核心数据,我创建了这个测试项目

我的建议是从一个标准的Apple模板开始。特别是,它们展示了如何使用NSFetchedResultsController来避免这类问题。

您还可以查看博客文章 Core Data Tutorial for iOS: How To Use NSFetchedResultsController