NSFetchRequest / Predicate问题

时间:2010-03-31 15:32:26

标签: iphone objective-c uitableview core-data nsfetchedresultscontroller

我有两个实体:患者和工作。患者与Job有很多关系称为“工作”,Job与患者有一对一的关系称为“患者”。 Job有'dueDate'(Date)和'completed'(BOOL)属性,Patient有'firstName'和'lastName'属性(两个字符串)。

我正在尝试为我的NSFetchedResultsController创建一个获取请求/谓词,我们抓取所有尚未完成的作业(即已完成==否)并按患者姓名划分它们。这是我的代码:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Job" inManagedObjectContext:moc];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(completed == NO)"];
[fetchRequest setPredicate:predicate];

NSSortDescriptor *patientDescriptor = [[NSSortDescriptor alloc] initWithKey:@"patient" ascending:YES];
NSSortDescriptor *dueDateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"dueDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:patientDescriptor, dueDateDescriptor, nil];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:@"patient" cacheName:@"Jobs"];

这是我的titleForHeaderInSection方法:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:section];
NSString *firstName = [[(Job *)[fetchedResultsController objectAtIndexPath:indexPath] patient] firstName];
NSString *lastName = [[(Job *)[fetchedResultsController objectAtIndexPath:indexPath] patient] lastName];

return [NSString stringWithFormat:@"%@ %@", firstName, lastName];

这似乎不起作用。我是以错误的方式解决这个问题吗?

3 个答案:

答案 0 :(得分:6)

它怎么不工作?它有助于描述您所看到的结果。

您没有将排序描述符添加到NSFetchRequest中,至少在您提供的示例中是这样。

您的排序描述符无效。似乎Patient是一种关系,因此对这种关系进行排序将不起作用。您可能希望进行如下排序:

NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"patient.lastName" ascending:YES];
NSSortDescriptor *firstNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"patient.firstName" ascending:YES];
NSSortDescriptor *dueDateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"dueDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: lastNameDescriptor, firstNameDescriptor, dueDateDescriptor, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

[lastNameDescriptor release], lastNameDescriptor = nil;
[firstNameDescriptor release], firstNameDescriptor = nil;
[dueDateDescriptor release], dueDateDescriptor = nil;

需要投放[fetchedResultsController objectAtIndexPath:indexPath],因为它会返回id。

你从[fetchedResultsController objectAtIndexPath:indexPath]的电话回来了什么?在此处设置一个断点并检查该值并确保您返回NSManagedObject而不是nil。在该方法中设置断点也将确认您正在被调用。

您的secondKeypathName将无法正常工作。您可能希望将其设置为@"patient.lastName",以便它与我上面描述的初始排序相匹配。

您的-tableView: titleForHeaderInSection:应该访问NSFetchedResultsController提供的缓存,而不是假设该部分中会有一行:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
{
    id sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo name];
}

最后,如果您希望该部分真正显示“姓氏,名字”格式,那么您需要在Patient实体上创建非瞬态派生值属性fullName,以便您可以根据它创建缓存。然后,只要更改了名字或姓氏,就需要更新此派生值。

答案 1 :(得分:3)

首先,您似乎没有将sortDescriptors附加到fetchRequests。这可能与问题有关,也可能没有。

其次,您可以更轻松地完成此任务。像这样:

sectionNameKeyPath:@"patient.name"

“name”应该是Patient对象的属性或方法。实现这一目标的一种简单方法是对患者采用分类方法:

- (NSString *)name {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

实际上,你无法通过这样简单的事情来实现你的目的,请阅读mzarra的答案以获得正确答案。 NSFetchedResultsController有这个批评意见:

  

如果控制器生成节,则数组中的第一个排序描述符用于将对象分组为多个节;它的键必须与sectionNameKeyPath相同,或者使用其键的相对排序必须与使用sectionNameKeyPath匹配。

但是,你不能对方法调用的结果进行排序,你需要一个对象的属性。所以,你最好的选择可能只是在“病人”上有一个“名字”属性,并使用该属性进行排序和sectionNameKeyPath。

答案 2 :(得分:2)

除了不将sortDescriptors分配给fetchRequest之外,我相信你的谓词有问题。由于您正在处理Core Data,因此“completed”属性的布尔值存储在NSNumber的实例中。类似下面的谓词会更好:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"completed = %@", [NSNumber numberWithBool:NO]];