10

I have an entity being displayed in a table view in just one section. The entity has two attributes, workoutName and trainingLevel. Both are of string type. Training level consists of the 3 types: 1, 2, 3. (trainingLevel = (Integer 16 or String Type? Which would be ideal?) I would like to split the table into three sections, each section containing entries for the corresponding training level.

How do I do this? The code I am currently using is below:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return self.workoutType.workouts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                  reuseIdentifier:CellIdentifier];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }


    WorkoutSet *workoutSet = [self.fetchedResultsController objectAtIndexPath:indexPath];


    cell.textLabel.text = workoutSet.workoutName;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"(%d)", workoutSet.days.count];    
}

-(void)fetchWorkoutSets
{

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"WorkoutSet"];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"workoutType = %@", self.workoutType];

    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"workoutName" ascending:YES];
    [fetchRequest setSortDescriptors:@[sortDescriptor]];
    [fetchRequest setPredicate:predicate];
    self.fetchedResultsController = [[NSFetchedResultsController alloc]
                                 initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext
                                 sectionNameKeyPath:nil cacheName:nil];

    NSError *error;
    if (![self.fetchedResultsController performFetch:&error])
    {
        NSLog(@"Fetch failed: %@", error);
    }
}

What I am struggling with is:

  • How to determine the number of rows for each section through the core data model by fetching number of entries with training level 1 or 2 or 3.
  • How to fill the rows of each section by fetching the correct items.
  • How to give a title to each section header.
memmons
  • 40,222
  • 21
  • 149
  • 183
user2512523
  • 1,229
  • 2
  • 15
  • 25
  • 3
    You're pretty much there. Just check the documentation for `NSFetchedResultsController` in particular the `sectionNameKeyPath` parameter of the designated initialiser, which you want to set as your `trainingLevel` property. – Rog Aug 21 '13 at 17:36
  • Also note that your `fetchedResultsController` getter should be performing the fetch, not `fetchWorkoutSet`, otherwise you'll have two different calls if you need to ensure the workout set has been fetched and you need fetchedResults. – memmons Aug 22 '13 at 00:00

1 Answers1

18

Here is a good tutorial on using fetchedResultsControllers: http://www.raywenderlich.com/999/core-data-tutorial-for-ios-how-to-use-nsfetchedresultscontroller

Create some properties to hold your context and fetches:

@property (nonatomic,strong)NSManagedObjectContext* managedObjectContext;
@property (nonatomic,retain)NSFetchedResultsController *fetchedResultsController;

In your fetchedResultsController property, use sectionKeyNamePath to set up your fetched results in sections:

- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription 
                                           entityForName:@"Workouts"
                                  inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
        initWithKey:@"workoutName" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
        [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
            managedObjectContext:managedObjectContext 
              sectionNameKeyPath:@"trainingLevel"
                       cacheName:@"Root"];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;

}

Your initial population of your fetchedResultsController can happen in your -viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
}

You'd then return the number of sections and number of rows in sections like this:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section
{
   id <NSFetchedResultsSectionInfo> sectionInfo = 
       [[[self fetchedResultsController] sections] objectAtIndex:section];

   return [sectionInfo numberOfObjects];        
}

You can then get your managed object for the particular row like this:

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

   // init the cell
   // and whatever other setup needed

   WorkoutSet *workoutSet = 
      [self.fetchedResultsController objectAtIndexPath:indexPath];

   // configure the cell from the managedObject properties
}
memmons
  • 40,222
  • 21
  • 149
  • 183
  • I have tried the above with no luck, Mainly having trouble towards the end where you have said to use NSManagedObject....Not sure how i can get to my data through that... Thanks – user2512523 Aug 22 '13 at 01:47
  • 1
    @user2512523 Updated with additional code to make it clearer. Your `WorkoutSet` objects are what are returned by the `fetchedResultsController`. – memmons Aug 22 '13 at 14:52
  • @user2512523 If this answer helped you, please mark it as accepted so the question doesn't show still open. – memmons Aug 26 '13 at 00:50