我目前正在开发一个具有几个实体和关系的应用程序,如下所示:
商品<< - >的类别即可。
我目前正在提取项实例,并使用项目category.name
在各个部分中显示它们。在这种情况下,我可以使用排序描述符按名称对类别进行排序,这非常简单,工作正常(下面的相关代码):
-(NSFetchedResultsController*)fetchedResultsController {
if (fetchedResultsController_ != nil)
return fetchedResultsController_;
NSManagedObjectContext *moc = [order_ managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:moc];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"category.name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:@"category.name"
cacheName:nil];
controller.delegate = self;
self.fetchedResultsController = controller;
[controller release];
[fetchRequest release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
// Error handling
}
return fetchedResultsController_;
}
我现在的问题是,我需要不是按名称对这些类别进行排序,而是通过属于类别实体的(NSNumber*) displayOrder
属性进行排序。 但是我需要在tableview上显示章节标题才能继续使用类别name
。
如果我将sortDescriptor设置为使用category.displayOrder
并将sectionNameKeyPath保持为category.name
,则部分标题可以正常工作,但fetchedDcriptor只是被fetchedResultsController忽略,表部分按类别名称排序(不知道为什么??)。
我的下一个想法是覆盖displayOrder
getter方法,但这并没有让我太过分,因为返回类型不同,而且我需要实际的displayOrder值来进行节排序。
所以现在我有一个感觉有点笨重的解决方案(下面的代码),我想知道是否有更好的方法来单独使用fetchedResultsController来实现同样的事情。
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// The code below grabs a reference to first object for a given section
// and uses it to return the associated category name
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSArray *menuItems = [sectionInfo objects];
if ([menuItems count] > 0)
{
MenuItem *menuItem = [menuItems objectAtIndex:0];
NSString *categoryName = menuItem.category.name;
return categoryName;
}
return [sectionInfo name];
}
我错过了一些基本的东西吗?
提前感谢您的想法。
罗格
答案 0 :(得分:1)
就排序而言,the documentation有这样的说法:
如果控制器生成节,则数组中的第一个排序描述符用于将对象分组为多个节;它的键必须与sectionNameKeyPath相同,或者使用其键的相对排序必须与使用sectionNameKeyPath匹配。
用英语(你可能已经知道这个Rog了,但是你可能不会再肯定那些后来搜索它的人可能会理解这个解释),这意味着如果你正在使用部分,那么NSFetchRequest上的排序必须对所有项目进行分组在同一部分一起。这可以通过使第一个排序标准为用作节名称的字段,或者可以通过使第一个排序标准成为导致相同类别分组的其他标准。
文档没有说明如果搞砸会发生什么事情;它可能会完全弄乱部分名称,重复部分,跳过部分,检测情况并“修复”您的排序,甚至只是崩溃。您的任何类别都有相同的displayOrder吗?
您的解决方案当然是可行的,如果您无法通过displayOrder正确排序,同时按category.name标题部分,则可能是您的最佳解决方案。
答案 1 :(得分:1)
为什么要提取Item
而不是Category
?如果我正确理解您的关系,Category
拥有与Item
的1对多关系,那么理论上Category
个实例应该有一个'items'属性,每个Item
都会返回在那个类别。
如果是这种情况,那么您只需获取所有类别,然后按displayOrder
对其进行排序。然后,忘记使用NSFetchedResultsController
本身中的部分。相反,您关联的tableView
方法看起来像:
- (NSInteger)numberOfSections {
return [[self.fetchedResultsController fetchedObjects] count];
}
- (NSInteger)numberOfRowsInSection:(NSInteger)section {
Category* category = [[self.fetchedResultsController fetchedObjects] objectAtIndex:section];
return [[category items] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
Category* category = [[self.fetchedResultsController fetchedObjects] objectAtIndex:section];
return category.name;
}
简而言之,我认为您通过提取Item
而不是Category
来过度复杂化,并尝试让NSFetchedResultsController
管理您的部分分组。它更简单,只需要更少的代码就可以自己进行部分管理。
答案 2 :(得分:1)
这是一个非常好的解决方案,Rog。
您当然不希望/需要子类NSFetchedResultsController。
@ aroth,我们没有足够的信息来了解他的对象模型的细节,但这些名称肯定意味着类别不属于项目。物品有一个类别。他的目的是显示一个项目列表,这就是他提取物品的原因。
答案 3 :(得分:0)
您可能需要子类化NSFetchedResultsController并自定义节名称函数。请参阅子类化的NSFetchedResultsController类文档。