4
\$\begingroup\$

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);
}
\$\endgroup\$
5
\$\begingroup\$

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);
}
\$\endgroup\$
  • \$\begingroup\$ Greatly Appreciated! That is so much more efficient and looks much better! \$\endgroup\$ – KFP Jan 15 '15 at 18:45
  • \$\begingroup\$ Hi Martin, Can I ask the reason behind using dot-syntax for the setters? I still use the explicit 'set' in the square brackets but was wondering if there are reasons apart from readability? \$\endgroup\$ – Tim Feb 12 '15 at 11:17
  • 1
    \$\begingroup\$ @Tim: There is actually no functional difference, see for example stackoverflow.com/questions/1249392/… and stackoverflow.com/questions/4259946/…. I prefer the dot notation for properties because you can directly see that you are working with a property and not with arbitrary methods. (And in Apple's "next generation language" Swift, there is only dot notation for properties.) \$\endgroup\$ – Martin R Feb 12 '15 at 17:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.