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.
Wher开发者_运维知识库e 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
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;
}
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 aNSURLRequest
for your JSON file. Also adds a loading view to the current view (I use aUIView
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) calledloaded
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 booleanloaded
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
}
}
You can open new view and show UIActivityIndicator with message for user, what you loading fresh data for him.
As for me, this is best choice, because interface remains responsible and user see what you actually do something and app not hanged.
精彩评论