user1828081
user1828081

Reputation: 81

Data from JSON Parsing straight to UITableView

I am getting data using json with this code and I need to display it in a tableview with two part code and name the problem is writing it all to an array is taking forever and the array comes back null. How can I get each returned element as its own tableview cell? Hundreds of airports are returned.

 NSString* path = @"https://api.flightstats.com/flex/airports/rest/v1/json/active?appId=id&appKey=appkey";

NSMutableURLRequest* _request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:path]];
[_request setHTTPMethod:@"GET"];
NSURLResponse *response = nil;
NSError *error = nil;

NSData* _connectionData = [NSURLConnection sendSynchronousRequest:_request returningResponse:&response error:&error];

if(nil != error)
{
    NSLog(@"Error: %@", error);
}
else
{
    NSMutableDictionary* json = nil;

    if(nil != _connectionData)
    {
        json = [NSJSONSerialization JSONObjectWithData:_connectionData options:NSJSONReadingMutableContainers error:&error];
    }
    if (error || !json)
    {
        NSLog(@"Could not parse loaded json with error:%@", error);
    }
    else
    {
        NSMutableDictionary *routeRes;
        routeRes = [json objectForKey:@"airports"];

        for(NSMutableDictionary *flight in routeRes)
        {
            NSLog(@"ident is %@", [flight objectForKey:@"name"]);
            NSString *code=[json objectForKey:@"fs"];
            NSString *name=[flight objectForKey:@"name"];
            NSLog(@"code %@, name %@", code, name);

            [candyArray addObject:[Candy code:code name:name]];
        }
    }
    _connectionData = nil;
    NSLog(@"connection done");

The following is the cellForRowatIndex were nothing is shown

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if ( cell == nil ) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    // Create a new Candy Object
    Candy *candy = nil;

    // Check to see whether the normal table or search results table is being displayed and set the Candy object from the appropriate array
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {
        candy = [filteredCandyArray objectAtIndex:[indexPath row]];
    }
    else
    {
        candy = [candyArray objectAtIndex:[indexPath row]];
    }

    // Configure the cell
    [[cell textLabel] setText:[candy name]];
    [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];

    return cell;
}

This is a sample of what the returned json is

{"airports":[{"fs":"CLO","iata":"CLO","icao":"SKCL","name":"Alfonso B. Aragon Airport","city":"Cali","cityCode":"CLO","countryCode":"CO","countryName":"Colombia","regionName":"South America","timeZoneRegionName":"America/Bogota","localTime":"2014-03-31T18:51:58.372","utcOffsetHours":-5.0,"latitude":3.543056,"longitude":-76.381389,"elevationFeet":3162,"classification":3,"active":true,"delayIndexUrl":"https://api.flightstats.com/flex/delayindex/rest/v1/json/airports/CLO?codeType=fs","weatherUrl":"https://api.flightstats.com/flex/weather/rest/v1/json/all/CLO?codeType=fs"}

This is the search function:

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope

{

// Update the filtered array based on the search text and scope.

    // Remove all objects from the filtered search array
[self.filteredCandyArray removeAllObjects];

// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",searchText];
NSArray *tempArray = [airportsArray filteredArrayUsingPredicate:predicate];
NSLog(@" text %@", searchText);


filteredCandyArray = [NSMutableArray arrayWithArray:tempArray];
NSLog(@"NSLog %@", scope);

}

Upvotes: 0

Views: 1550

Answers (2)

meda
meda

Reputation: 45490

What's up with that candy object?

You have an array of dictionnary, here's how you parse that:

Get the array:

NSArray *airportsArray = [json objectForKey:@"airports"];

Set the cell text:

[[cell textLabel] setText:[[airportsArray objectAtIndex:indexPath.row]objectForKey:@"name"]];
[[cell detailTextLabel] setText:[[airportsArray objectAtIndex:indexPath.row]objectForKey:@"code"]];

or for better readability:

NSDictionary *airportAtIndex = [airportsArray objectAtIndex:indexPath.row];
[[cell textLabel] setText:[airportAtIndex objectForKey:@"name"]];
[[cell detailTextLabel] setText:[airportAtIndex objectForKey:@"code"]];

Can you elaborate on how I could use sendAsynch to speed up the process?

Ok, first thing to note, you are not speeding up anything here, the reason why you feel the UI is lagging is because you run the network request on the main thread.

You can solve that problem by sending the request asynchrously, meaning in a background thread which will not freeze your User Interface.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //this is where you perform the network request
    //You can fetch data, in your case get the JSON
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //in this block you want to manipulate the the User Interface
        //this is where you reload the tableView
        //or stop an activity indicator
        [self.tableView reloadData];
    });
});

Things to note (from @HotLicks)

The app must be set up so that the TableView delegate will initially (before the data is downloaded) report zero rows in the section. Then, the reloadData op will cause the TableView to refresh the table. So initially the table will be blank. One could fudge it slightly to initially present a single cell saying "Data is loading" or anything that lets the user know >that an operation is in progress such as a UIActivityIndicator.

read up on Grand Central Dispatch (GCD)

Upvotes: 3

Barbara R
Barbara R

Reputation: 1057

You could take several approaches here in order to improve performance.

  1. Start uploading and requesting airports as soon as possible in your application.
  2. Complimentarily try to perform any heavy operation in a background thread, dispatching an asynchronous operation to build you array of Candy objects. You can use dispatch_async.
  3. Another approach would be to have some kind of custom logic to avoid creating the whole array at a time… I would keep for example the JSON result (NSMutableDictionary *routeRes) and would create Candy objects on demand (every time a cell is required), keeping a trace of the last Candy index read / created in the JSON up to finish parsing all the dictionary (then you can start reading your array of candies)…. That could work if Candy creation logic is not too heavy (I think it's not).

Upvotes: 0

Related Questions