Displaying Core Data: If attribute has same name display once

北慕城南 提交于 2019-12-12 09:58:56

问题


I have viewed numerous predicate questions, I have read the docs and nothing seems to be jumping out as an answer my problem.

I have a Core Data entity named Materials and I have the Attributes category, subcategory and description.

I have three UITableViewControllers and in each I want to use a predicate to display as follows:

TableViewController 1: Only the categories (no repeating of category names)

Select a category and go to TableViewController 2.

TableViewController 2: Display Subcategories (no repeating of subcategory names)

Select a subcategory and go to TableViewController 3 listing all items in that category and subcategory.

Without using three entities in a Core Data Model, can I do this?

I have tried using the following predicate code inside my fetchedResultsController method but to avail:

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;

This is the first time I have attempted to sort and display this way, I would usually use a predicate of a relationship as is common practice but it seemed illogical to have 3 entities for one set of data - Materials.


回答1:


You need not three different NSMO for each Materials, Category and Sub category. You only need one NSMO that is Materials which has these Attributes category, subcategory and description.

For Showing Categories in 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);

With this you can fetch all the Materials NSManagedObjects with distinct categories from Core data.

For Showing SubCategories in ViewController 2:

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);

With this you can fetch all the Materials NSManagedObjects with distinct categories from Core data.

For third Viewcontroller to list all the items belong to a Selected category and subcategory use:

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);



回答2:


A. There is nothing wrong in having three entities. You do not have three entities for one set of data. You would have one entity (Material) for one set of data (materials), one entity for another set of data (subcategories) and one entity for another set of data (categories). (To be more precise: you would have three entity types for three types of data sets).

Modelling the structure into different entity types does not mean that you give up the data set of materials. You still have that.

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

B. However, if you want to have attributes instead of relationships you have to do that different.

Let's say that the category and subcategory are identified by its name. (This is another mistake, but this mistake is the consequence of the first one.)

You have to pass the name of the category selected in the first view controller to the second one. Then you can build the predicate using that name:

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



回答3:


If you want to stick with category and subcategory as attributes rather than relationships, another option would be to use the NSFetchedResultsControllers to derive the distinct values for you.

In your first tableViewController, specify category as the sectionNameKeyPath for the FRC. Then in your table view datasource methods, use the FRC's sections property to populate your tableView and cells. For example,

- (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;
}

And so on for other delegate/datasource methods.

Likewise in your second table view controller, you would include a predicate to restrict the fetch to those Materials with the relevant category, and specify the FRC's sectionNameKeyPath as subcategory. Then use the same trick as above to populate the cells with the section data (which will in this case be the subcategories) from the FRC.

Finally, in your third table view controller, just use a predicate to restrict the results to the relevant category and subcategory and implement the FRC and tableView delegate/datasource methods in the normal way.



来源:https://stackoverflow.com/questions/27538930/displaying-core-data-if-attribute-has-same-name-display-once

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!