Search code examples
iosobjective-cmultithreadingreloaddata

UITable won't refresh even with reload called on main thread


I have a main view controller(SecondViewController) with a UITable and a navigation controller. When a navigation bar button is pressed, a menu drops down from the navigation bar on top of the table. This menu is created by adding a view controller as a subview like so:

//SecondViewController.m
self = sortMenu.secondVC;
[self addChildViewController:sortMenu];
[self.view addSubview:sortMenu.view];
[sortMenu didMoveToParentViewController:self];

sortMenu contains a button that changes the order the cells are displayed in by calling a class method of the main view controller.

//SortMenuViewController.m
- (IBAction)sortButtonPressed:(id)sender {
    [_secondVC sortButtonPressed:[sender tag]];

} 

In sortButtonPressed, it calls a method to make a fetch request with updated sort filter value.

//SecondViewController.m
-(void)sortButtonPressed:(NSInteger)sortDescriptor{
    _sortDescriptor = sortDescriptor;
    currentPredicate = [NSPredicate predicateWithFormat:@"dataset & %d > 0", 4];
    [self fetchResultsUsingSegmentedControlIndex];
}

The fetch request is performed and returns the data in a new order.

//SecondViewController.m
- (IBAction)fetchResultsUsingSegmentedControlIndex
{
    NSString* sectionNameKeyPath = nil;
    NSArray* sortDescriptors = nil;
    NSSortDescriptor *scientificNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"scientificName" ascending:YES];
    NSSortDescriptor *commonNameFirstDescriptor = [[NSSortDescriptor alloc] initWithKey:@"commonNameFirst" ascending:YES];
    NSSortDescriptor *commonNameLastDescriptor = [[NSSortDescriptor alloc]
                                                  initWithKey:@"commonNameLast"
                                                  ascending:YES
                                                  selector:@selector(localizedCaseInsensitiveCompare:)];

    if (_sortDescriptor == kSortByCommonNameFirst )
    {
        sortDescriptors = [[NSArray alloc] initWithObjects:commonNameFirstDescriptor, commonNameLastDescriptor, scientificNameDescriptor, nil];
        sectionNameKeyPath = @"commonNameFirst";
    }
    else if (_sortDescriptor == kSortByCommonNameLast )
    {
        sortDescriptors = [[NSArray alloc] initWithObjects:commonNameLastDescriptor, commonNameFirstDescriptor, scientificNameDescriptor, nil];
        sectionNameKeyPath = @"commonNameLast";
    }
    else if (_sortDescriptor == kSortByScientificName )
    {
        sortDescriptors = [[NSArray alloc] initWithObjects:scientificNameDescriptor, commonNameFirstDescriptor, commonNameLastDescriptor, nil];
        sectionNameKeyPath = @"scientificName";
    }

    NSError *error;

    NSLog(@"current predicate: %@", currentPredicate);

    [[self fetchedResultsControllerWithsectionNameKeyPath:sectionNameKeyPath sortDescriptors:sortDescriptors predicate:currentPredicate] performFetch:&error];


    [scientificNameDescriptor release];
    [commonNameLastDescriptor release];
    [commonNameFirstDescriptor release];
    [sortDescriptors release];

    NSUInteger sectionsCt = [[speciesFetchedResultsController sections] count];
    int sum = 0;
    for (int i=1; i < sectionsCt; i++){
        id <NSFetchedResultsSectionInfo> sectionInfo = [[speciesFetchedResultsController sections] objectAtIndex:i];
        NSUInteger numOfObj = [sectionInfo numberOfObjects];
        NSLog(@" in section %d number of objects is  %lu ", i, (unsigned long)numOfObj);
        sum  = sum + numOfObj;
    }


    [_table performSelectorOnMainThread:@selector(reloadData)
                                     withObject:nil
                                  waitUntilDone:NO];
}

When I call fetchResultsUsingSegmentedControlIndex from the main view controller (before dropping down the sort menu), it works correctly. However, when called from sortMenu, numberOfRowsInSection, numberOfSectionsInTableView, and cellForRowAtIndexPath are not called. I have tried to call reloadData on the main thread with performSelectorOnMainThread and also dispatching it to the main queue, but neither works.

I originally created a sort menu by adding a pickerview to the main view controller on pressing the navigation bar button, and my table reloaded correctly. Since creating a separate view controller for the menu (to have greater design control), it doesn't work.


Solution

  • Ended up using delegation.

    //  SortMenuViewController.h
    
    #import <UIKit/UIKit.h>
    
    @protocol SortMenuViewControllerDelegate <NSObject>
    -(void)sortButtonPressed:(NSInteger)sortDescriptor;
    -(void)viewButtonPressed:(NSInteger)viewDescriptor;
    @end
    
    @interface SortMenuViewController : UIViewController{
    
    }
    
    //SortMenuViewController.m
    - (IBAction)changeSort:(id)sender {
    
        [_delegate sortButtonPressed:[sender tag]];
    
    }
    
    //SecondViewController.h
    @interface SecondViewController : UIViewController <NSFetchedResultsControllerDelegate, SortMenuViewControllerDelegate>{
    
    }
    -(void)sortButtonPressed:(NSInteger)sortDescriptor{
        _sortDescriptor = sortDescriptor;
        currentPredicate = [NSPredicate predicateWithFormat:@"dataset & %d > 0", dataset];
        [self fetchResultsUsingSegmentedControlIndex];
    }