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
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 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.
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With