Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to load data in UITableViewController?

I am currently loading data coming from a JSON service in the viewDidLoad method in UITableViewController. The problem is that is the data takes time to be retrieved and parsed, the view takes time to be created. Where is the best place to load this data? I assume that there is a hook somewhere to load data after the view is created. By doing this I will be able to use some UIActivityIndicatorView in the final view. Thanks

like image 223
Christophe HAMERLING Avatar asked Jul 26 '11 22:07

Christophe HAMERLING


2 Answers

Finally here is a solution based on comments: Launch a thread in viewDidLoad to get data without blocking all:

- (void) viewDidLoad
{
    dataLoaded = NO;

    [self initSpinner];
    [self launchLoadData];
...
}

-(void)launchLoadData {
    NSLog(@"Launching thread");
    [NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
}

- (void) loadData {
    dataLoaded = NO;
    NSLog(@" thread launched");
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [self loadDataFromURL:nil];
    dataLoaded = YES;
    [self.tableView reloadData];
    [pool release];
}

- (void)loadDataFromURL:(NSString*)url {
    // start the spinner to show that loading may be time consuming...
    [NSThread detachNewThreadSelector: @selector(spinBegin) toTarget:self withObject:nil];
    JSONLoader *loader = [[JSONLoader alloc] init];
    self.accounts = [loader getAccountsFromURL:@"http://foo/bar/repository.json"];
    [loader release];
    //[NSThread sleepForTimeInterval:3];
    [NSThread detachNewThreadSelector: @selector(spinEnd) toTarget:self withObject:nil];
}

and use the flag to display or not data in table. tableView reloadData will do the rest when called from thread.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (dataLoaded) return [self.accounts count];
    return 0;
}
like image 98
Christophe HAMERLING Avatar answered Sep 18 '22 18:09

Christophe HAMERLING


I think what you're trying to ask is the workflow for displaying data from a web service in a UITableView.

Here's what I recommend:

  • Your viewDidLoad makes a NSURLRequest for your JSON file. Also adds a loading view to the current view (I use a UIView with a black bg (0.5 alpha), plus a label and UIActivityIndicator). In this method you also set a BOOL ivar (which you need to add in your header) called loaded to NO.

  • You concat your NSURLRequest data as it comes down into a mutable data object.

  • When your NSURLRequest finishes, you turn it's data into a string, and parse the JSON into an array of some sort (or dictionary if you want). In the same method you remove the loading view, and change your boolean loaded to YES. You then tell the tableView to reload it's data: [self.tableView reloadData];

Here's where the magic happens... in your table view methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (loaded) return [myArrayOfJSONObjects count];
    return 0; // Will only return 0 if the data is not downloaded
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSUInteger row = [indexPath row];

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell...
    if (loaded) {
        cell.textLabel.text = [myArrayOfParsedJSONObjects objectAtIndex:row];
        //Anything else you want to set
    }
    else {
        //Do nothing :) - you shouldn't reach this else anyway because your numberOfRows method should stop it
    }
}
like image 44
Alex Coplan Avatar answered Sep 20 '22 18:09

Alex Coplan