显示核心数据:如果属性具有相同名称,则显示一次

时间:2014-12-18 03:47:57

标签: ios objective-c core-data nspredicate predicate

我查看了很多谓词问题,我已经阅读了文档,似乎没有任何内容可以作为我的问题的答案。

我有一个名为 Materials 的核心数据实体,我有属性类别子类别 description

我有三个UITableViewControllers,每个我想使用一个谓词来显示如下:

TableViewController 1:仅限类别(不重复类别名称)

选择一个类别并转到TableViewController 2。

TableViewController 2:显示子类别(不重复子类别名称)

选择一个子类别并转到TableViewController 3,列出该类别和子类别中的所有项目。

在核心数据模型中不使用三个实体,我可以这样做吗?

我尝试在fetchedResultsController方法中使用以下谓词代码,但可以使用:

Materials * materials = [[Materials alloc]init];//this doesn't feel like it belongs inside a fetchedResultsController

NSPredicate * predicate = [NSPredicate predicateWithFormat:@"category == %@", materials.category];

fetchRequest.predicate = predicate;

这是我第一次尝试排序和显示这种方式,我通常会使用关系的谓词作为常规做法,但对于一组数据有3个实体似乎不合逻辑 - 材料。

3 个答案:

答案 0 :(得分:2)

每种材料,类别和子类别不需要三种不同的NSMO。您只需要一个NSMO,它是具有这些属性类别,子类别和描述的材料。

用于在ViewController 1中显示类别:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Materials"];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Materials" inManagedObjectContext:self.managedObjectContext];

// Required! Unless you set the resultType to NSDictionaryResultType, distinct can't work. 
// All objects in the backing store are implicitly distinct, but two dictionaries can be duplicates.
// Since you only want distinct Categories, only ask for the 'Category' property.
fetchRequest.resultType = NSDictionaryResultType;
fetchRequest.propertiesToFetch = [NSArray arrayWithObject:[[entity propertiesByName] objectForKey:@"Category"]];
fetchRequest.returnsDistinctResults = YES;

// Now it should yield an NSArray of distinct values in dictionaries.
NSArray *dictionaries = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
NSLog (@"names: %@",dictionaries);

使用此功能,您可以从Core数据中获取具有不同类别的所有Materials NSManagedObjects。

在ViewController 2中显示SubCategories:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Materials"];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Materials" inManagedObjectContext:self.managedObjectContext];


NSPredicate * predicate = [NSPredicate predicateWithFormat:@"SELF.category == %@", selectedCategoryName];

fetchRequest.predicate = predicate;
// Required! Unless you set the resultType to NSDictionaryResultType, distinct can't work. 
// All objects in the backing store are implicitly distinct, but two dictionaries can be duplicates.
// Since you only want distinct SubCategory, only ask for the 'SubCategory' property.
fetchRequest.resultType = NSDictionaryResultType;
fetchRequest.propertiesToFetch = [NSArray arrayWithObject:[[entity propertiesByName] objectForKey:@"SubCategory"]];
fetchRequest.returnsDistinctResults = YES;

// Now it should yield an NSArray of distinct values in dictionaries.
NSArray *dictionaries = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
NSLog (@"names: %@",dictionaries);

使用此功能,您可以从Core数据中获取具有不同类别的所有Materials NSManagedObjects。

为第三个Viewcontroller列出属于Selected类别和子类别的所有项目:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Materials"];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Materials" inManagedObjectContext:self.managedObjectContext];


NSPredicate * predicate = [NSPredicate predicateWithFormat:@"SELF.category == %@ and SELF.subcategory == %@", selectedCategoryName,selectedSubcatgory];

fetchRequest.predicate = predicate;
// Required! Unless you set the resultType to NSDictionaryResultType, distinct can't work. 
// All objects in the backing store are implicitly distinct, but two dictionaries can be duplicates.

// Now it should yield an NSArray of distinct values in dictionaries.
NSArray *dictionaries = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
NSLog (@"names: %@",dictionaries);

答案 1 :(得分:1)

一个。有三个实体没有错。一组数据没有三个实体。您将拥有一组实体(材料)用于一组数据(材料),一个实体用于另一组数据(子类别),一个实体用于另一组数据(类别)。 (更确切地说:对于三种类型的数据集,您将有三个entity types。)

将结构建模为不同的实体类型并不意味着您放弃了材料的数据集。你还有。

http://en.wikipedia.org/wiki/Second_normal_form

B中。但是,如果您想拥有属性而不是关系,那么您必须做到与众不同。

假设类别和子类别由其名称标识。 (这是另一个错误,但这个错误是第一个错误的结果。)

您必须将在第一个视图控制器中选择的类别的名称传递给第二个视图。然后,您可以使用该名称构建谓词:

NSPredicate * predicate = [NSPredicate predicateWithFormat:@"category == %@", self.passedName];

答案 2 :(得分:1)

如果您希望坚持使用categorysubcategory作为属性而不是关系,那么另一种选择是使用NSFetchedResultsControllers为您推导出不同的值。

在第一个tableViewController中,将category指定为FRC的sectionNameKeyPath。然后在表视图中使用数据源方法,使用FRC的sections属性来填充tableView和单元格。例如,

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [[self.fetchedResultsController sections] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][indexPath.row];
    cell.textLabel.text = sectionInfo.name
    return cell;
}

等等其他委托/数据源方法。

同样在您的第二个表视图控制器中,您将包含一个谓词来限制对具有相关category的材质的提取,并将FRC的sectionNameKeyPath指定为subcategory。然后使用与上面相同的技巧,使用FRC中的节数据(在本例中为子类别)填充单元格。

最后,在第三个表视图控制器中,只需使用谓词将结果限制为相关的categorysubcategory,并以正常方式实现FRC和tableView委托/数据源方法。 / p>