NSFetchedResultsController 部分按类排序

Posted

技术标签:

【中文标题】NSFetchedResultsController 部分按类排序【英文标题】:NSFetchedResultsController section sorting by class 【发布时间】:2014-05-05 22:54:38 【问题描述】:

我需要使用

将我的对象分类
[[NSFetchedResultsController alloc] initWithFetchRequest:request 
                                    managedObjectContext:context 
                                      sectionNameKeyPath:sectionName 
                                               cacheName:nil];

我想按他们的class 对它们进行排序。例如,MyObjectType 类型的对象进入一个部分,OtherObjectType 类型的对象进入第二个部分,这两种对象类型都将出现在结果中,因为 OtherObjectType 继承自 MyObjectType。在上述方法中将@"class" 作为sectionNameKeyPath 参数传递似乎可行。但是,为了获得正确的排序,我还需要NSFetchRequest 的排序描述符来根据类进行排序:

NSSortDescriptor *sectionDescriptor = [NSSortDescriptor
                                       sortDescriptorWithKey:@"class"
                                       ascending:YES];

使用这种排序描述符会给我错误Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath class not found in entity

为了清楚起见,这里是我想要工作的全部代码:

  NSFetchRequest* myRequest = [[NSFetchRequest alloc] 
                                 initWithEntityName:@"myEntityName"];

  NSSortDescriptor *nameDescriptor = [NSSortDescriptor 
                                      sortDescriptorWithKey:@"myName"
                                      ascending:YES];

  NSSortDescriptor *sectionDescriptor = [NSSortDescriptor
                                           sortDescriptorWithKey:@"class"
                                           ascending:YES];
  request.sortDescriptors = @[sectionDescriptor, nameDescriptor];

  [[NSFetchedResultsController alloc]
     initWithFetchRequest:myRequest
     managedObjectContext:myContext
     sectionNameKeyPath:@"class"
     cacheName:nil];

【问题讨论】:

【参考方案1】:

请记住,您只能在使用一个实体及其子实体时执行此操作,因为 NSFetchRequest 需要一个实体来搜索(您可以指定也搜索子实体)。

您需要声明一个属性,该属性标识您希望检索和重新组合的正确记录类型。因为 class 是一个运行时值,所以您需要能够使用在底层存储中使用的标识符。因此,在您的特定情况下,我将在所有子实体的父实体上使用常量(字符串或数字)属性来标识该记录属于哪个子组。

【讨论】:

对。我忘了提到我正在处理的类都是我使用结果控制器获取的类的子实体。所以,他们都在那里。我只需要按类对它们进行排序。目前我在父实体上使用字符串属性来标识该部分。我希望我能摆脱那个财产。 该属性可以帮助您,因为它允许您在持久存储级别而不一定在内存中执行此操作(除非您使用的是内存存储)。如果使用 SQLite,这比在内存中执行并查找每个实体/子实体的类成员的运行时值要快得多。简而言之,你已经做得很好了。 我什至没有想到进行运行时变量检查的成本。总之,我认为这是最好的方法。我将保留我当前使用的属性,将它们分成多个部分。【参考方案2】:

您不能使用单个 FRC 执行此操作,因为 NSFetchRequest 只能绑定到单个 NSManagedObject 子类。相反,您可以使用多个获取的结果控制器并在查找对象时手动设置部分索引。

【讨论】:

不一定。它们与单个实体相关联,其中可以包括子实体。 我想这是一个公平的观点,因为您可以遍历对象图,但这充其量只是间接的。不过,thoughtadvances 试图在这里用 sectionNameKeyPath 完成是不可能的……相信我,我自己已经尝试过足够多次了。假设他还没有您建议的子关系结构,他要么需要使用单独的 FRC,要么需要自己处理 fetch 请求。 我的意思是,只要它们来自同一个子实体树,您就可以只使用一个 FRC 来完成此操作。您不能做的是在继承中使用彼此不关联的不同实体。 是的,您需要在适当的情况下手动偏移 indexPath.section(例如 NSFetchedResultsController 委托方法),但这是完全可行的,并不像您想象的那么难。我以前做过很多次,效果很好。只需确保清理样板 NSFetchedResultsController 委托方法以反映两者的节索引均为 0 的事实(遗憾的是,您不能为第二个控制器创建空的第 0 节),否则您可以正常使用它们。 我同意@J2theC 的观点,如果您可以使用继承来避免第二个 FRC,那么这是可取的。

以上是关于NSFetchedResultsController 部分按类排序的主要内容,如果未能解决你的问题,请参考以下文章

在 Core Data 应用程序中调用 performFetch 后,是不是需要手动更新表视图?