BalestraPatrick
BalestraPatrick

Reputation: 10144

NSFetchedResultsController get particular value

I'm building an app for a shop in which you can register sales and order them by day. I have a splitViewController and I'm using the template code that comes with the project. I have my NSFetchedResultsController which gets all my managed objects. These objects contain all the details of a sale (day, price, time, totalPrice). I want to create an array with all the different days. Here is an example. These are the sales I retrieve with my NSFetchedResultsController:

Monday 25th

Monday 25th

Tuesday 26th

Wednesday 27th

I want to get an array like this:

Monday 25th

Tuesday 26th

Wednesday 27th

And I want this as data source for my master TableView. When the user will tap a row, it will pass all the managed objects of that day to the detail TableView.

The problem is that I can't find a way to retrieve this in the fetchedResultsController and set it as data source. If I set my array as data source and I add a day, I get:CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. attempt to insert row 4 into section 0, but there are only 2 rows in section 0 after the update with userInfo (null)

There is a problem with the delegate of NSFetchedResultsController. Here is my code:

- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
    return _fetchedResultsController;
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sale" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];

// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
NSArray *sortDescriptors = @[sortDescriptor];

[fetchRequest setSortDescriptors:sortDescriptors];

// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
     // Replace this implementation with code to handle the error appropriately.
     // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

_arrayOfDays = [NSMutableArray new];

[[_fetchedResultsController fetchedObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if (![_arrayOfDays containsObject:[obj valueForKeyPath:@"date"]]) {
        [_arrayOfDays addObject:[obj valueForKeyPath:@"date"]];
    }
}];

NSLog(@"%@", _arrayOfDays);

return _fetchedResultsController;
}

And here my numberOfRowsInSection:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(@"Number of self.arrayOfDays: %d", (int)_arrayOfDays.count);
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
//return [sectionInfo numberOfObjects];
return self.arrayOfDays.count;
}

Upvotes: 0

Views: 503

Answers (1)

Patrick Goley
Patrick Goley

Reputation: 5417

The issue is that your fetch request does not match what you actually want to display. You can't tell your FRC to fetch these objects BUT only show a single row for any items with a matching date, it simply doesn't have that flexibility. You have manually done that filtering yourself, so any time the FRC changes any object, you need to redo that manual filtering in controllerDidChangeContent:. Inserts from the FRC won't make sense because the FRC doesn't know that you're using an altered version of the array to back the table view. Please post your code for willChangeContent:, didChangeObject:, and didChangeContent.

Honestly it sounds like this would be much more simple and direct if you had a SaleDate entity, that had a to-many relationship to Sales. In this view you would simply fetch SaleDates, and load the detail tableview with any Sales associated to the selected SaleDate. This prevents you from having to manually filter and manager your own array, the FRC has it covered. This would be a much better approach for what you want to accomplish.

Upvotes: 1

Related Questions