Search code examples
iosobjective-cuitableviewnsfetchedresultscontrolleruisegmentedcontrol

NSFetchedResultsController retrieval of specific data during sorting


I've created an NSFetchedResultsController object & loaded it up with data from a Core Data entity (called "AssetsPartners"). This entity has many different attributes, such as name, type, photo, etc.. Currently, I use the name attribute during data fetch and this brings back everything. Now I need to be able to sort what's inside the NSFetchedResultsController when pressing on one of the 3 UISegmentedControl buttons by the 'type' attribute. The type attribute contains only 3 possible values: all, asset & counterparty. Index 0 = "All", index 1 = "Assets", index 2 = "Counterparty". So when the user clicks on index 1, for instance, which is "Assets", I want to pull out only that type of data from my NSFetchedResultsController before displaying that data in the table view. How do I do this?

Here's how I create the NSFetchedResultsController:

-(NSFetchedResultsController *)fetchedResultsController
{
    //Is there already anything in that instance variable? Not equalling to nil means there's something alreayd there. Just return it & we're done.
    if (_fetchedResultsController != nil)
    {
        return _fetchedResultsController;
    }


    //IF we make it past the previous if statement, we'll have to make the previous object.
    //We need a NSFetchRequest & a sort descriptor to create a NSFetchedResultsContoller.

    NSFetchRequest *fetchRequest    = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity     = [NSEntityDescription entityForName:@"AssetsPartners" inManagedObjectContext:[AppDelegate shared].managedObjectContext];
    [fetchRequest setEntity:entity];


    //Specify how the fetched objects should be sorted.
    NSSortDescriptor *assetName = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; //type //Sorts data by name. In this case by "name"'s first letter of the alphabet.
    [fetchRequest setSortDescriptors:@[assetName]]; //@[fetched, assetType, dateSD];


    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                    managedObjectContext:[AppDelegate shared].managedObjectContext
                                                                      sectionNameKeyPath:nil    //'nil' brings data back in one long list. But writing "author", for instance, would split data by work written by each different author.
                                                                               cacheName:nil];  //Not sure what this does...


    _fetchedResultsController.delegate = self; //"Look to me for any of your delegate methods".

    return _fetchedResultsController;
}

After I have my data, I place it into the table view:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //Has to be here to be accessible by any object that requires it regarding of scope.
    AssetsPartners *items;


    //Segmented control stuff. Simply filter fetched array data rather than creating everything cell-related from scratch.
    if(_segmentedControl.selectedSegmentIndex == 0)
    {
        items = [_fetchedResultsController objectAtIndexPath:indexPath]; //Ask '_fetchedResultsController' what's at this particular indexPath right now. Also alphabetically sorts the array list.
    }
    else if(_segmentedControl.selectedSegmentIndex == 1)
    {
        //Sorts table view alphabetically.
        //[self.elements sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"lastName" ascending:YES]]];
    }
    else
    {

    }




    CustomTableCell *aCell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCell"]; //Cells are dequeued & reused.
    if (aCell == nil)
    {
        aCell = [[CustomTableCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"CustomCell"];


        UILabel *label  = [[UILabel alloc] initWithFrame:CGRectMake(65.0, 15.0, 150.0, 30.0)];
        label.textColor = [UIColor whiteColor];
        label.tag       = 999; //Neccessary to have this to by-pass scope & access this label outside this if statement (Chosen number is random).
        [aCell.contentView addSubview:label];




        //Entirely new UIImageView for every UITableViewCell (to tweak the frame size & position).
        UIImageView *newImgView = [[UIImageView alloc] initWithFrame:CGRectMake(10.0, 15.0, 35.0, 35.0)];
        newImgView.tag          = 1000;
        [aCell.contentView addSubview:newImgView];
    }


    //Makes sure the separator doesn't have that little gap in the beginning.
    //NOTE: This MUST be here and "_tableView.separatorInset = UIEdgeInsetsZero;" must exist inside [self extraTableViewParameter]!
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
    {
        aCell.layoutMargins                     = UIEdgeInsetsZero;
        aCell.preservesSuperviewLayoutMargins   = NO;
    }




    /*CELL DETAILS.*/
    aCell.backgroundColor           = [UIColor clearColor];
    aCell.textLabel.textColor       = [UIColor clearColor];
    aCell.detailTextLabel.textColor = [UIColor lightGrayColor];


    /*FILL CELL WITH DATA.*/
    aCell.textLabel.text        = @"";
    NSInteger anInteger         = [items.balance integerValue];
    aCell.detailTextLabel.text  = [NSString stringWithFormat:@"%@ P", [self addWhitespacesTo:anInteger]];


    UILabel *label  = (UILabel *)[aCell.contentView viewWithTag:999]; //Casting UILabel to access the previously created one.
    label.text      = items.name;


    //1 - Reduce 'photo' characters to bare essentials. Which is just an image name.
    NSString *iconName      = [self cutOutString:@"bizzer://" fromString:items.photo]; //Get rid of "bizzer://" from string value.

    //2 - Utilize previously created UIImageView for this cell with the image name.
    UIImageView *imgView    = (UIImageView *)[aCell.contentView viewWithTag:1000];
    imgView.image           = [UIImage imageNamed:iconName];
    [self turnIcon:imgView toColor:items.color];

    return aCell;
}

Solution

  • You can update fetchRequest NSPredicate associated with NSFetchResultController. Here is sample code.

    -(void)updateFetchRequestForType:(NSString *)type
    {
        [NSFetchedResultsController deleteCacheWithName:@"Root"];  
    
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"type == %@",type];
        [_fetchedResultsController.fetchRequest setPredicate:predicate];
        NSError *error = nil;
        if (![[self fetchedResultsController] performFetch:&error]) {   
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
        }
        [table reloadData];
    }
    

    Note: Set your cacheName to Root While initializing NSFetchResultController in your code.