1
votes

I have a UITableView With a custom Cell that contains another UItableView. I need to pass an object to it, and then execute a fetchrequest based on this object.

From my cellForRowAtIndexPath method, I am passing a Managed Object to the custom Cell, like this:

TWHistoryViewStandardExpendedCell *cell = (TWHistoryViewStandardExpendedCell *)[tableView dequeueReusableCellWithIdentifier:ExpandedCell];

if (cell == nil) {
    cell = (TWHistoryViewStandardExpendedCell *)[[[NSBundle mainBundle] loadNibNamed:@"HistoryViewStandardCellExpanded" owner:self options:nil] objectAtIndex:0];
}

Day *aDay = (Day *)[_fetchedResultsController objectAtIndexPath:indexPath];     
[cell setViewingDay: aDay]; // NSLog here returns the expected object! :)
return cell;

This way, I should be able to execute a fetchRequest based on this object, from my custom Cell.

On my custom UItableViewCell, I do this:

- (void) awakeFromNib
{    
    [self fetchRequest];
}

- (void)fetchRequest {

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

Some details about my fetchedResultsController: see in comments that my managed object returns null here!

- (NSFetchedResultsController *)fetchedResultsController
{

    if (_fetchedResultsController) {
        return _fetchedResultsController;
    }

    NSManagedObjectContext * managedObjectContext =
        [myAppDelegate managedObjectContext];

NSEntityDescription *entity  =
[NSEntityDescription entityForName:@"Clock"
            inManagedObjectContext:managedObjectContext];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];

[fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"day == %@", _viewingDay]];

NSLog(@"_viewingDay: %@", _viewingDay); // returns null! :(
NSLog(@"_viewingDay.clocks: %@", _viewingDay.clocks); // also returns null!

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"clockIn" ascending:NO];

NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
//
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:20];

NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                    managedObjectContext:managedObjectContext
                                      sectionNameKeyPath:nil
                                               cacheName:nil];

_fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;

return _fetchedResultsController;
}

Based on this, I have overriden my setViewingDay method:

- (void)setViewingDay:(Day *)viewingDay
{
    if (_viewingDay != viewingDay) {
        _viewingDay = viewingDay;
        NSLog(@"setViewingDay: %@", _viewingDay); // returns expected object! =)
        [self fetchRequest];
    }
}

Still, after this, my UITableView remains empty. My numberOfRowsInSection method keeps returning 0!

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

    NSLog(@"numberOfRowsInSection %d", [sectionInfo numberOfObjects]);

    return [sectionInfo numberOfObjects];
}

I also added a UIButton that performs the fetch request. Hoping to find a situation where the fetchRequest was being performed before the actual setting of my reference to the managed object. So I click on it, do perform a fetch. And nothing! No rows whatsoever.

EDIT: However, the NSLogs bellow, from inside my fetchResultsController do return an object then, by using a supporting UIBUtton and IBAction. But still no rows!

NSLog(@"_viewingDay: %@", _viewingDay);
NSLog(@"_viewingDay.clocks: %@", _viewingDay.clocks);

Supporting UIButton to perform a fetch:

- (IBAction)fetchem:(UIButton *)sender {

    [_clocksTableView reloadData];
    _fetchedResultsController = nil;
    [NSFetchedResultsController deleteCacheWithName:nil];
    [self fetchRequest];

    NSLog(@"\n\nfetchem: %@ \n\nvd: %@  \n\nclocks: %@ ", _fetchedResultsController.description, _viewingDay.description, _viewingDay.clocks.description );
}

Anything I might be missing here?

Thank you!

EDIT 2:

I just realized that setting my predicate to (1 == 1), returns all clocks. Confirming that my resultsController is correctly set up. There may be something wrong with my predicate... I don't see what. I have a similar predicate in a previous controller and works great.

Predicate is very simple, nothing fancy:

[fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"day == %@", _viewingDay]];

I have a Clock and Day entities.

A Day has many clocks. 1 to many relationship.

A clock has one day, and one day only.

enter image description here

The fetchRequest above should have been returning all clocks from that day. But it's not?

1
Have you checked that your fetchedresults controller is correctly setup before asking it to performFetch?Abizern
Yes I have. It's a rather simple model. Clock entity contais a relationship to Day entity. I'm fetching all Clock objects, that match a given Day object. If there is a problem with my fetchedResultsController, I'm not seeing it yet.nmdias

1 Answers

1
votes

1) awakeFromNib gets execute the moment you instantiate the cell and therefore before you set the viewing day. It also doesn't get execute if the cell is reused, so you should trigger the fetch request separately.

2) How does the fetchedResultsController property inside the cell get set?

EDIT 1:

From the datamodel and the predicate, it would seem the relationship between clock and day doesn't get set correctly.

EDIT 2:

Quoting the asker's comment from below: "The problem was fixed after inserting: [self fetchRequest] inside my overriden setter."