views:

54

answers:

2

I have noticed that a problem in my app is caused because the Datasource methods of the UITableView are called before viewDidLoad.

The problem is that the UITableView doesn't have the correct amount of rows, it gets the amount of rows from the NSFetchedResultsController but the performFetch "function" for that is called in the viewDidLoad method which for some reason is called after the Datasource methods.

Here's the source of the two important methods:

- (void)viewDidLoad {
    [super viewDidLoad];

 self.tableView.allowsSelectionDuringEditing = NO;
 self.tableView.editing = YES;
 self.title = [NSString stringWithFormat:@"%@", [[game valueForKey:@"title"] description]];

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

}

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

How do I get past this problem?

A: 

In my current app, the general code flow would tend to be:

(in the parent controller:)

  • Build the NSFetchRequest based on the relevant parameters of the parent controller.
  • Perform the fetch with NSFetchedResultsController's -performFetch: method
  • If there were no errors, create the results view controller and associate the fetched results controller with it

This approach avoids the issue you're having. It also means that the view that displays results doesn't need to have search logic, and can be reused to show different result sets (though the same result can be achieved by passing in the NSFetchRequest).

Seamus Campbell
This is unnecessary. You do not need to perform a fetch before the `NSFetchedResultsController` is built, that is wasteful. In addition, `-viewDidLoad` is called before the view appears so it is normal behavior to initialize the `NSFetchedResultsController` in the `-viewDidLoad` call. If you are seeing different behavior there is something wrong.
Marcus S. Zarra
@Marcus: I'm not performing a fetch "before the `NSFetchedResultsController`" is built (via `NSManagedObjectContext -executeFetchRequest`?) and I'm not sure why you read me as doing so. I've edited a little bit above to try to make that more clear. If there's some other reason you think it's wasteful, though, I'd appreciate your clarification.
Seamus Campbell
+1  A: 

The normal program flow calls for the -viewDidLoad to be called before any of the UITableView data source methods. If you are getting them in the reverse order then there is something in your code base causing them to be called out of order.

First, put a breakpoint in both of the methods you have shown in this question and confirm that they are being called out of order.

Then, look at the stack trace when you are in the -tableView:numberOfRowsInSection: breakpoint and see why it is being called before the -viewDidLoad.

Update

The -viewDidLoad is most definitely being called first as shown in the link. When you select the [PlayerViewController -viewDidLoad] line in that stack trace, what line of code is it sitting on? If it is sitting on [super viewDidLoad] then what is your superclass and what is it doing it's -viewDidLoad?

Marcus S. Zarra
Breakpoints confirm my assumption. Here's the stack trace in `-tableView:numberOfRowsInSection:`: http://fwdr.org/gt3o. How would i find out why it is happening?
Joshua
Updated answer with another query.
Marcus S. Zarra
Your Update helped greatly, it turned out it was sitting on the line of code which enabled editing in the `UITableView` (i didn't include this code in the question, and yes I know I should of). It took the app to a different method and didn't return it back to `-viewDidLoad`. I simply fixed the problem by putting the line of code in question to the end of the method.
Joshua
It's interesting as this worked fine when I was using the 3.1.3 SDK but now with the 4.0 SDK it wouldn't work. Thanks again for your help.
Joshua