HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Using NSPredicate with NSFetchRequest in a NSFetchedResultsController

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
nsfetchedresultscontrollerwithusingnspredicatensfetchrequest

Problem

I am learning CoreData and I wanted to have my code reviewed. As usual, I get something to work, then I attempt to refine it.
I have a data model that consists of an Item entity and a subItem entity. The Item has a 'to many' relationship with the subItem and subItem has a 'to one' relationship with Item. Basically Item can have multiple subitems, but subitem can only be tied to one Item. My initial tableview displays the items and selecting a row segues to a tabbarcontroller that consists of other controllers, one being another tableview. That tableview displays the subitems of the Item. This is the code I have in my viewDidLoad:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *subItemEntity = [NSEntityDescription entityForName:@"KFPSubItem" inManagedObjectContext:self.managedObjectContext];

[fetchRequest setEntity:subItemEntity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"item = %@", self.record];

//add sort descriptors
[fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];

//initialize fetchedresultscontroller
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

//configure fetched results controller
[self.fetchedResultsController setDelegate:self];

[self.fetchedResultsController.fetchRequest setPredicate:predicate];

//perform Fetch
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];

if (error) {
    NSLog(@"Unable to perform fetch");
    NSLog(@"%@, %@", error, error.localizedDescription);
}

Solution

The entity and the sort descriptors of NSFetchRequest are defined as "properties"

@property(nonatomic, strong) NSEntityDescription *entity;
@property(nonatomic, strong) NSArray *sortDescriptors;


So while calling the setter methods still works

[fetchRequest setEntity:...];
[fetchRequest setSortDescriptors:...];


you should use the "dot-Syntax" for properties:

fetchRequest.entity = ...;
fetchRequest.sortDescriptors = ...;


and the same applies to the properties of NSFetchedResultsController.

The creation of the fetch request can be simplified with the
factory method

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"KFPSubItem"];


I usually assign the sort descriptors to separate variables first. This may
be a matter of taste, but it avoids too long statements if there is more
than one sort descriptor:

NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortByName];


The

self.fetchedResultsController = [[NSFetchedResultsController alloc] ...


line is extremely long and should be split into several lines.

The correct way to check for success or failure of Cocoa (Touch) methods is
documented in
"Handling Error Objects Returned From Methods" in the "Error Handling Programming Guide":


Important: Success or failure is indicated by the return value of the
method. Although Cocoa methods that indirectly return error objects in
the Cocoa error domain are guaranteed to return such objects if the
method indicates failure by directly returning nil or NO, you should
always check that the return value is nil or NO before attempting to
do anything with the NSError object.

So instead of

NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
if (error) { ... }


you should do

NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) { .... }


Putting it all together:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"KFPSubItem"];

NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortByName];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"item = %@", self.record];
fetchRequest.predicate = predicate;

self.fetchedResultsController = [[NSFetchedResultsController alloc]
                                initWithFetchRequest:fetchRequest
                                managedObjectContext:self.managedObjectContext
                                  sectionNameKeyPath:nil
                                           cacheName:nil];
self.fetchedResultsController.delegate = self;

NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
    NSLog(@"Unable to perform fetch");
    NSLog(@"%@, %@", error, error.localizedDescription);
}

Code Snippets

@property(nonatomic, strong) NSEntityDescription *entity;
@property(nonatomic, strong) NSArray *sortDescriptors;
[fetchRequest setEntity:...];
[fetchRequest setSortDescriptors:...];
fetchRequest.entity = ...;
fetchRequest.sortDescriptors = ...;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"KFPSubItem"];
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortByName];

Context

StackExchange Code Review Q#77601, answer score: 5

Revisions (0)

No revisions yet.