Cocoa touch 如何切换UITableView';NSFetchedResultsController(或其谓词)是否以编程方式?

Cocoa touch 如何切换UITableView';NSFetchedResultsController(或其谓词)是否以编程方式?,cocoa-touch,uitableview,core-data,nsfetchedresultscontroller,master-detail,Cocoa Touch,Uitableview,Core Data,Nsfetchedresultscontroller,Master Detail,我有一个UITableView,它显示了大量名为“Documents”的实体的子集。子集由另一个实体“Selection”定义。选择是命名的、有序的文档列表 它工作正常,除非我想在运行时更改显示的选择。我只有一张空白名单 基本上,我需要更改NSFetchedResultsController持有的谓词,以便新谓词使用另一个选择。我不能让它工作。我的最后一次尝试是完全摆脱NSFetchedResultsController并重新分配它: - (void) displaySelection:(Sel

我有一个UITableView,它显示了大量名为“Documents”的实体的子集。子集由另一个实体“Selection”定义。选择是命名的、有序的文档列表

它工作正常,除非我想在运行时更改显示的选择。我只有一张空白名单

基本上,我需要更改NSFetchedResultsController持有的谓词,以便新谓词使用另一个选择。我不能让它工作。我的最后一次尝试是完全摆脱NSFetchedResultsController并重新分配它:

- (void) displaySelection:(Selection *)aSet
{
 self.currentSelection = aSet;
 self.fetchedResultsController = nil;
 // methods here don't all use the property but directly the ivar, so we must trigger the getter
 [self fetchedResultsController];
 [self.tableView reloadData];
}
当然,NSFetchedResultsController getter做了正确的事情:

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

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"DocInSelection" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"selection.identifier like %@", currentSelection.identifier];
    [fetchRequest setPredicate:predicate];
<snip>
    [fetchRequest setSortDescriptors:sortDescriptors];
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
<snip>
    return fetchedResultsController;
}
-(NSFetchedResultsController*)fetchedResultsController
{
如果(fetchedResultsController!=nil){return fetchedResultsController;}
NSFetchRequest*fetchRequest=[[NSFetchRequest alloc]init];
NSEntityDescription*entity=[NSEntityDescription entityForName:@“DocInSelection”在managedObjectContext:managedObjectContext中];
[FetchRequestSetEntity:entity];
NSPredicate*谓词=[NSPredicate谓词格式:@“selection.identifier like%@”,currentSelection.identifier];
[FetchRequestSetPredicate:谓词];
[FetchRequestSetSortDescriptors:sortDescriptors];
NSFetchedResultsController*aFetchedResultsController=[[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@“Root”];
aFetchedResultsController.delegate=self;
self.fetchedResultsController=aFetchedResultsController;
返回获取的ResultsController;
}
此代码第一次起作用,因为已设置初始选择。但是,当调用
displaySelection:
时,tableview变为空白

会议上提出了一个非常类似的问题

答案是摆脱NSFetchedResultsController。我不想这样做,因为NSFetchedResultsController在这里带来了很多有用的东西(例如缓存、部分加载…)。问题仍然存在:如何在NSFetchedResultsController支持的UITableView中“切换”数据,其中“切换”意味着具有不同的谓词,甚至(在我的情况下)具有不同的实体

请注意,出于完整性的考虑,由于从选择到文档的多对多关系是有序的,因此它通过称为DocInSelection的中间轻量级实体进行处理,该实体具有“ordering”属性以及与文档和选择的两个多对一关系


谢谢你的建议。

在我发布我的问题后,我尝试了另一个问题的OP所显示的代码的变体。它对我有用。这是:

- (void) displaySelection:(Selection *)aSet
{
    if (aSet != self.currentSelection) {
        self.currentSelection = aSet;

        NSFetchRequest *fetchRequest = [[self fetchedResultsController] fetchRequest];
        NSPredicate *predicate = nil;
        NSEntityDescription *entity = nil;
        entity = [NSEntityDescription entityForName:@"DocInSelection" inManagedObjectContext:managedObjectContext];
        predicate = [NSPredicate predicateWithFormat:@"selection.identifier like %@", currentSelection.identifier];
        [fetchRequest setEntity:entity];
        [fetchRequest setPredicate:predicate];

        [NSFetchedResultsController deleteCacheWithName:@"Root"];

        NSError *error = nil;
        if (![[self fetchedResultsController] performFetch:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }       
    }
    [self.tableView reloadData];
}

由于NSFetchedResultsController(FRC)是一个对象,因此可以像存储任何其他对象一样存储它的实例

一种有用的技术是初始化多个FRC并将其存储在字典中,然后将tableview控制器的
fetchedResultController
属性设置为当前需要的FRC。这在某些情况下非常有用,例如使用分段控件对同一表中的不同属性或实体进行排序。这种技术的优点是可以维护单个FRC缓存,从而显著加快抓取速度


只需确保在交换控制器之前向tableview本身发送一个
beginUpdates
,然后在交换完成后发送一个
endUpdates
。这样可以防止在交换FRC时,表格在狭窄的窗口中请求数据。然后调用
reloadData

虽然这可能有效,但iOS参考库中有一条注释让我感到困扰:

重要提示:您不能修改 获取请求。例如,你必须 不更改其谓词或排序 订单

资料来源:

iOS 3.2参考库中不存在此附加说明


我只是想指出这一点。

一个重要的注意事项:如果“覆盖”fetchController对象,请确保首先清除其.delegate-否则在删除行时会崩溃,等等,因为旧的fetchController及其委托会获得事件。

啊!有趣。由于选择集取决于用户操作,因此对我来说,这可能不是一个正确的想法。不过我会记住的。谢谢。既然UICollectionView没有相应的方法,你会如何在它上进行beginUpdate/EndUpdate?我没有注意到这一点。如果我们能从苹果那里得到一个解释,那将是最好的。我有点理解它:由于FetchedResultController保留其获取结果,因此从其脚下拉出fetchRequest地毯可能会导致不一致。这就是为什么上面的代码片段1-清除缓存,2-再次执行获取请求,3-要求tableView重新加载其数据。现在看来还可以,但我想有一些正式的说法。如果每次都要删除CacheWithName:@“Root”,为什么还要创建缓存呢。如果不使用缓存,请传入一个缓存名nil。尽管缓存是使用NSFRC的一个好处。我认为,虽然当前选择(可能很大)保持不变,但是
NSFetchedResultController
使用缓存的效果很好。“每一次”可能不是那么频繁。此外,苹果在“如果您正在使用缓存,请将其删除(使用deleteCacheWithName:)”。苹果还添加了“如果您正在更改获取请求,通常不应使用缓存”。测试应该有助于确定缓存在这里是否有益。