views:

795

answers:

2

Hello everyone,

I am trying to create a NSFetchRequest that produces results for a UITableView.

It should find all the distinct occurrences of a NSString property and split them into alphabet sections ('A', 'B', 'C', etc.)

I have set up a method on my NSManagedObject class to return the first letter of the property:

- (NSString *)entrantFirstLetter
{
     [self willAccessValueForKey:@"entrantFirstLetter"];
     NSString *returnString = [self.entrant substringToIndex:1];
     [self didAccessValueForKey:@"entrantFirstLetter"];
     return returnString;
}
  • I set 'sectionNameKeyPath' to @"entrantFirstLetter" and this works perfectly

  • However, I now need to set returnsDistinctResults to YES

  • But, returnsDistinctResults only works if propertiesToFetch is set, so

  • I set propertiesToFetch to "entrant" (the property I'm interested in)

  • But, in order for propertiesToFetch to work, the resultType must be NSDictionaryResultType, so

  • I set resultType to NSDictionaryResultType

  • But, this resultsType means that my 'sectionNameKeyPath' of @"entrantFirstLetter" no longer works.

So, you'd think the answer was to add in 'entrantFirstLetter' to the propertiesToFetch? But as it's not a property on the NSEntityDescription I can't!

All I want to do is sort a list of strings in Core Data into alphabet sections and not have duplicates. I can get each part working on its own, but getting it all working together relies on a seemingly endless loop of dependencies and I can't find a way to get it all working.

Any ideas would be much appreciated,

Russell.

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Project" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSDictionary *properties = [entity propertiesByName];
NSArray *propertiesToFetch = [NSArray arrayWithObject:[properties objectForKey:@"entrant"]];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:propertiesToFetch];
[fetchRequest setReturnsDistinctResults:YES];
NSSortDescriptor *entrantDescriptor = [[NSSortDescriptor alloc] initWithKey:@"entrant" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:entrantDescriptor]];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:@"entrantFirstLetter" cacheName:nil];
+1  A: 

You are trying to duplicate the NSFetchResultsController's default section behavior.

Instead, just set the sectionNameKeyPath: to entrant and the FRC will create the sections for you with no more effort on your part.

TechZen
That would group every entrant it its own section.
Russell Quinn
No, it would work just like the Contacts app. It groups in a section all `Property` objects whose `entrants` attribute start with the same letter. If want customized behavior, you can subclass NSFetchResultsController. See the class' docs for details.
TechZen
You can also just add a method to your core data entity class to return a custom section string, and specify that in the sectionName keypath
Mike Weller
@Mike Weller -- You can do that but it breaks incapsulating by putting display logic inside the model. What happens when you need multiple custom sections? Do you modify the model for every change. What happens when you change the interface? What happens if you want to reuse the model for another app? We use MVC for a reason.
TechZen
Just put it in a category. The fact is that the sectionNameKeypath has to be on the object itself, so you don't have much choice. If it's on a category it's fairly well separated.
Mike Weller
No, its not. A category is just source file management. It has nothing to do with compiled encapsulation. You are still needlessly loading up the model logic with view code. It's just as easy to write a custom FRC subclass and you can write a different subclass for each view if necessary. That way, your model stays clean i.e. it simulates the real-world objects, conditions or events it is supposed instead of getting involved in how that data is displayed.
TechZen
A: 

So, in the end this would not work at all with the NSFetchResultsController (this was under the 3.1.3 SDK). I just did my own NSFetchRequest in loadView that sorts all entrants into arrays according to their initial letter and at the same time stores the valid section header names.

Maybe Apple fixed the problem described in 4.x, but I haven't needed this functionality since or updated this project.

Russell Quinn