3

我正在结合 NSFetchedResultsController 实现 UITableViewController。当 UITableViewController 被实例化时,NSFetchedResultsController 会根据用户在前一个控制器上所做的选择使用不同的谓词构造(基本上与CoreDataBooks示例相同)。
有时我以这种方式设置谓词:

predicate = [NSPredicate predicateWithFormat:@"container = %@", aManagedObject];

有时以这种方式:

predicate = [NSPredicate predicateWithFormat:@"container IN (%@)", aNSMutableSetOfObjectsID];

两个谓词都可以正常工作,因为它们按预期正确获取了我的所有对象。当我在设置第二个谓词时尝试将新的托管对象插入列表时会出现问题。事实上,在这种情况下,FRC 委托方法永远不会被调用,因此 tableview 不会自动更新。
我确定新对象已正确添加到 FRC 使用的同一上下文中,并且已设置其“容器”关系,以便应触发委托,但事实并非如此!

我试过的:

我说第二个谓词工作正常,因为如果我添加一个新对象,然后弹出 UITableViewController 并再次推送它,强制重新获取所有数据,新对象会毫无问题地出现在列表中。
我进行的另一个测试是在添加新对象后立即强制重新计算 FRC:

NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
    exit(-1);
}
[self.tableView reloadData];

新对象正确显示。

代码:

- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController == nil) {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *managedObjectContext = realEstate.managedObjectContext;

    [fetchRequest setEntity:[NSEntityDescription entityForName:@"Item" inManagedObjectContext:managedObjectContext]];       
    [fetchRequest setPredicate:[self getBasePredicate]];

    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" 
                                                                   ascending:YES 
                                                                    selector:@selector(localizedCaseInsensitiveCompare:)];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:nameDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
    [nameDescriptor release];
    [sortDescriptors release];

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                                                                managedObjectContext:managedObjectContext 
                                                                                                  sectionNameKeyPath:@"sectionIndex" 
                                                                                                           cacheName:nil];
    self.fetchedResultsController = aFetchedResultsController;
    fetchedResultsController.delegate = self;
    [aFetchedResultsController release];
    [fetchRequest release];
}

return fetchedResultsController;
}


// return a predicate for the fetchedResultsController
- (NSPredicate *)getBasePredicate {
    NSPredicate *predicate = nil;

    if ([[managedObject valueForKey:@"subcontainersCount"] intValue] == 0)
        // container without sons   **(FIRST PREDICATE)**
        predicate = [NSPredicate predicateWithFormat:@"container = %@", managedObject];
    else {
        // container with sons    **(SECOND PREDICATE)**
        predicate = [NSPredicate predicateWithFormat:@"container IN (%@)", [Container allDescendantsObjectID:(Container *)managedObject includeSource:YES]];
    }

    return predicate;
}


- (void)addNewItem {
    Item *newItem = (Item *)[NSEntityDescription insertNewObjectForEntityForName:@"Item" 
                                                          inManagedObjectContext:realEstate.managedObjectContext];
    newItem.name = @"my new item";
    newItem.container = aContainerManagedObject;

    NSError *error = nil;
    if (![realEstate.managedObjectContext save:&error]) {
        abort();
    }
}

我使用的 NSFetchedResultsControllerDelegate 方法取自“更多 iPhone 3 开发”。完整的代码可以在这里查看(第 30-31、35 页)。
如果需要,我可以在这里发帖。

4

1 回答 1

2

解决了将对象 ID 替换NSManagedObject为谓词的问题。

前:[NSPredicate predicateWithFormat:@"container IN (%@)", aNSMutableSetOfObjectsID];

后:[NSPredicate predicateWithFormat:@"container IN (%@)", aNSMutableSetOfNSManagedObject];

由于某些原因,如果谓词使用 ID 而不是确切的 NSManagedObjects 获取对象,则不会调用 FRC 委托。
我正在 iPhoneOS 3.1.3 和 3.2 上进行测试。但是 iPhoneOS 4.0 应该同时支持 objectsID 和 NSManagedObject 并正确调用 FRC 委托方法,但我现在无法在 4.0 上进行测试。

于 2010-07-03T12:24:56.120 回答