views:

48

answers:

1

This is probably a stupid question with an easy answer. I'm new to iOS dev and this is killing me.

I have a basic tab bar app. The app loads the initial tab upon launch and it is a tableview controller. The data for this tableview is supplied by a datacontroller where it creates an array from data fetched from the internet. When I first launch the app nothing is displayed in the tableview, it's empty. However, if I select a different tab and then go back to that tab the data is now there and displayed in the tableview as it should. How do I get the data to display the first time around? It's obviously there. I believe it may be something to do with where/when the data is loading that is causing the problem, any insight would be great.

This sets the datacontroller in the app delegate:

// Create Locations data controller.
LocationDataController *controller = [[LocationDataController alloc] init];
self.locationDataController = controller;
[controller release];
locationsViewController.locationDataController = locationDataController;

Here's the datacontroller code:

@implementation LocationDataController
@synthesize fetchConnection = mFetchConnection;
@synthesize locations, tempLocations;



-(id)initData {
    if (self = [super init]) {
        [self createData];
    }
    return self;
}

-(id)init {
    [self fetchData];
    return self;
}


-(unsigned)countOfList {
    return [locations count];
}


-(Location *)objectInListAtIndex:(unsigned)theIndex {
    return [locations objectAtIndex:theIndex];
}


-(void)dealloc {
    [locations release];

    if (mFetchConnection != nil) {
        [mFetchConnection cancel];
        [mFetchConnection release];
    }

    if (mFetchConnectionBuffer != nil)
        [mFetchConnectionBuffer release];

    [super dealloc];
}


#pragma mark -
#pragma mark Fetching/Sending Data
#pragma mark

- (void)fetchData {
    if (mFetchConnection == nil) {
        if (mFetchConnectionBuffer != nil)
            [mFetchConnection release];

        mFetchConnectionBuffer = [[NSMutableData alloc] init];

        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:kFetchURLPath]];
        self.fetchConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES] autorelease];
        [request release];
    }
}




#pragma mark -
#pragma mark NSURLConnection Delegate
#pragma mark

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)inData {
    if (connection == mFetchConnection) {
        [mFetchConnectionBuffer appendData:inData];
    }
}




- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)connectionError {
    if (connection == mFetchConnection) {
        self.fetchConnection = nil;
        [mFetchConnectionBuffer release];
        mFetchConnectionBuffer = nil;
    }
}



- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    tempLocations = [[NSMutableArray alloc] init];

    if (connection == mFetchConnection) {
        NSString *str = [[NSString alloc] initWithData:mFetchConnectionBuffer encoding:NSUTF8StringEncoding];
        SBJSON *parser = [[SBJSON alloc] init];
        id result = [parser objectWithString:str error:nil];
        if (result != nil && [result isKindOfClass:[NSArray class]])
            [tempLocations setArray:result];
        [str release];
        [mFetchConnectionBuffer release];
        mFetchConnectionBuffer = nil;
        self.fetchConnection = nil;

        [self initData];

    }
}


-(void)createData {

    // Cycle through array to implement locations.
    Location *location;
    NSMutableArray *array = [[NSMutableArray alloc] init];

    // create arry of locations.
    for (int i=0; i<[tempLocations count];i++) {

        location = [[Location alloc] init];
        location.name = [[tempLocations objectAtIndex:i] objectForKey:@"name"];
        location.address = [[tempLocations objectAtIndex:i] objectForKey:@"address"];
        location.city = [[tempLocations objectAtIndex:i] objectForKey:@"city"];
        location.state = [[tempLocations objectAtIndex:i] objectForKey:@"state"];
        location.zip = [[tempLocations objectAtIndex:i] objectForKey:@"zip"];

        [array addObject:location];
        [location release];

    }

    self.locations = array;
    [array release];
    [tempLocations release];

}
A: 

Assume you have properly implemented the TableView delegate methods, I'd suggest you call tableView.reloadData after the data has been created to see if that works.

Max
I tried that, but seemed to have no luck. - [self.tableView reloadData] this was in viewWillApear. Also tried in viewDidLoad with no luck.
You are loading data asynchronically so the data may not be ready when you called it. Just a guess.
Max
That was the conclusion I was beginning to come to, any thoughts/ideas on what I can do to revise it. I'm kind of at a loss as to how to approach getting this resolved. It works, but seems like it is displaying the view prior to the data being ready and I'm not sure how to fix the issue in the scheme of things.
I'd try call reloadData after [self initData] in connectionDidFinishLoading to see if works.
Max
Makes sense, but how can I do that when I'm in the DataController class?
Perhaps you can change your code so it won't automatically pull data when the data object is created. So you have the chance in the view controller to let it fetch the data and get a notification when it is done.
Max
It turns out we were correct. Since the data was being loaded asynchronously it wasn't ready when the view was displayed. I set up a simple notification that was called when the data was finished loading. It triggered the notification in the main view to reload the table data. Works like a charm. I also had a similar issue in a different view that required pre-determined input before connecting to the DB and returning the data. I solved this as you mentioned by setting a method that sends the input to the data class prior to its connection to the DB. Worked great. Thanks for your help.