iPhone4 iOS5 NSFetchedResultsController如何在子类中正确设置委托?

时间:2011-11-17 22:06:22

标签: objective-c uitableview ios5 iphone-4 nsfetchedresultscontroller

我有一个处理所有UITableview持久数据管理和UITableView行managemetn的父类。我已经从一个新的XCode4项目中复制了大部分代码,其中包含UITableview的持久数据。现在我正在尝试删除子类中的tablerow,并且在删除行时不会调用任何委托方法,从而导致我的tableview处于不一致状态。

我是否正确分配了代理人?在这种情况下,谁是NSFetechedResultsController的代表? 我是否需要明确地将我的子类设为NSFetchedResultsControllerDelegate?

以下是我检索NSFetchedResultsController的方法,注意它如何将self指定为委托。

- (NSFetchedResultsController *)fetchedResultsController
{
    if (__fetchedResultsController != nil)
    {
        return __fetchedResultsController;
    }

    /*
     Set up the fetched results controller.
    */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];

    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:fetchBatchSize];

    // Edit the sort key as appropriate.
//    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"startMinute" ascending:YES];
    NSArray *sortDescriptors;
    if(sortDescriptor2!=nil)
    {
     sortDescriptors= [[NSArray alloc] initWithObjects:sortDescriptor,sortDescriptor2, nil];
    }else
    {
     sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    }
    [fetchRequest setSortDescriptors:sortDescriptors];

    if(filterPredicate != nil)
    {
        [fetchRequest setPredicate:filterPredicate];
    }

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;



    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error])
        {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
//      abort();
    }

    return __fetchedResultsController;
}  

当删除表行时,即使认为表行确实被删除,也不会调用任何委托方法。为了调试这个问题,我添加了以下2个断言。第二个断言失败了。

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    id delegate = self.fetchedResultsController.delegate;


    NSAssert(delegate!=nil,@"Tableview is not delegate of fetched results controller!");

//this assertion fails
    NSAssert([((UITableViewController*)self) isEqual:delegate],@"Tableview is not delegate of fetched results controller!");

    if (editingStyle == UITableViewCellEditingStyleDelete)
    {


        // Delete the managed object for the given index path
        NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];

        [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

        // Save the context.
        NSError *error = nil;
        if (![context save:&error])
        {
            /*
             Replace this implementation with code to handle the error appropriately.

             abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
             */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
//            abort();
        }
    }   
}

谢谢!

2 个答案:

答案 0 :(得分:1)

设置NSFetchedResultsController的代码看起来是正确的。它的委托设置为self意味着它的委托是你创建它的对象。这看起来像是tableView的委托的同一个对象。您还可以正确删除对象并保存上下文。

您未显示的内容可能是崩溃的原因是您处理NSFetchedResultsController委托方法。至少,您需要添加以下内容:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView reloadData];
}

当fetchedResultsController检测到managedObjectContext中的更改时,这将强制表重新加载。

如果这不是您的问题,那么您需要发布更多代码,说明如何配置类以及如何处理fetchedResultsController委托方法。

编辑:修正了错误的签名om controllerDidChangeContent:

答案 1 :(得分:1)

您必须使用这些方法让NSFetchedResultsController能够对表格视图中的更改做出反应:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;
{
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type) {
        case NSFetchedResultsChangeInsert:
            // your code for insert
        break;
        case NSFetchedResultsChangeDelete:
           // your code for deletion
        break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
    {

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

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

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        break;

        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}

同时使用NSFetchedResultsController的ViewController监听 NSFetchedResultsControllerDelegate