3

我目前遇到一个问题,当 FRC 的 fetchRequest 上的 fetchLimit 为 4 时,使用 NSFetchedResultsController 的 UITableViewController/UITableView 显示大约 86 个项目。我知道 86 个项目满足 fetch 本身,并且我知道它们出现的原因是因为 didChangeObject: atIndexPath... 被 86 个中的每一个调用,并且我按默认实现方式插入。

我的问题是为什么 fetchLimit 不限制 NSFetchedResultsController 尝试“更改”(在这种情况下插入)的对象数量?

我的应用程序用例是第一个选项卡显示我在应用程序启动时(在侧线程上)获得的典型提要项目。我将它们保存在单独的上下文中的 CoreData 中,最终合并到主线程的上下文中并针对更改的内容启动 FRC 回调。我的问题专门针对不存在任何项目的初始情况。


这是我的fetchRequest:

    NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
fetchRequest.entity = [NSEntityDescription entityForName:ENTITY_CONTENT_ITEM inManagedObjectContext:managedObjectContext];

// Set a limit on the number of items returned
[fetchRequest setFetchLimit:4];

// Set a Predicate to limit the fetch to featured items only
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"featured == YES AND contentType == %d", contentType]];

// Set the sort descriptors
NSSortDescriptor *sortDateDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"sortDate" ascending:NO] autorelease];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDateDescriptor]];

上面的 contentType 只是一种区分应该在此选项卡与其他选项卡中显示的内容的方法。Featured 是项目的布尔属性,它更像是一个用于显示目的的开关。

这是我的didChangeObject:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 
  switch(type) {
    case NSFetchedResultsChangeInsert:
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;
    case NSFetchedResultsChangeDelete:
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;
    case NSFetchedResultsChangeUpdate:
      [tableView cellForRowAtIndexPath:indexPath];
      break;
    case NSFetchedResultsChangeMove:
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
       // Reloading the section inserts a new row and ensures that titles are updated appropriately.
       [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
       break;
  }
}

我知道这个问题很难回答,但即使是解释 FRC 如何决定调用 didChangeObject 的次数也会非常有帮助。

4

1 回答 1

1

https://devforums.apple.com/thread/60319?tstart=0

对于那些可以访问它的人,请检查一下。苹果开发者对 iOS4.0 中 CoreData/NSFetchedResultsController/UITableViewController 堆栈的变化进行了很好的快速总结。

3.2 和 4.0 中进行了更改以改进缓存和性能以及修复已知问题。持久缓存更具侵略性,因此滥用 cacheName 的人遇到了麻烦。将 cacheName 设置为 nil,或者清理使用情况并在适当时调用 +deleteCacheWithName 是解决方案。部分重新计算得到改进,以尽可能通过数据库而不是内存来执行更多计算。每当重建缓存时(或者如果不使用缓存,则在调用 performFetch 时)都会触发分段。.description 解决方法使 keypath 引用未建模的属性(-description 方法),这会导致部分计算在内存中工作,因为 db 不知道任何关于 -description 的信息。

在 4.0 中,还对 UITableView 进行了更改,以修复一些涉及 UITableViewController 委托回调的问题。需要在早期 iOS 版本上使用 -reloadData 来解决问题的人应该能够在 iOS4 上使用更细粒度的回调。

-本特(苹果)

鉴于此,我在我的 fetchedResultsController initWithFetchRequest 调用中将 .description 添加到我的 sectionNameKeyPath 中。这显然使部分计算发生在内存而不是磁盘上,这解决了我的部分认为他们拥有比实际更多的项目的问题。

这适用于 4.0,而在 3.0 中,我只需从 controllerDidChangeContent 回调中调用 reloadData。如果您有类似的问题,请随时给我留言。

于 2010-07-27T20:11:44.440 回答