Sandy
Sandy

Reputation: 3

How to execute the API method before tableview is loaded?

The requirement is to call edmunds API and display the vendors name in a table as soon as the app launches.

1) -getAPIData()

Retrieves the names of dealers and stores in self.dealerName array.

-(void)getAPIData{
    NSURLSession *session = [NSURLSession sharedSession];
    self.task = [session dataTaskWithURL:[NSURL URLWithString:[NSString stringWithFormat:
                                                @"https://api.edmunds.com/api/dealer/v2/dealers?zipcode=%@&radius=%@&fmt=json&api_key=ycwedw68qast829zx7sn9jnq",
                                                @"01609",@"10"]]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
      if (data.length > 0 && error == nil)
      {
          NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data
                                                                   options:kNilOptions
                                                                     error:NULL];
          self.dealersDictionary = jsonData[@"dealers"];
          for (id item in self.dealersDictionary){
              if (item[@"name"] != nil){
                  self.dealerName = item[@"name"];
                  NSLog(@"%@",self.dealerName);
              }else{
                  NSLog(@"could'nt find the names");
              }
          }
      }
  }
 ];
}   

2) -viewDidLoad()

This method calls getAPIData(above method).

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self getAPIData];
}

3) -(NSInteger)tableView:(UITableView *)tableview numberOfRowsInSection:(NSInteger)section

Returns the dealers count.

-(NSInteger)tableView:(UITableView *)tableview numberOfRowsInSection:(NSInteger)section
{
    [self.task resume];
    return self.dealerName.count;
}

getAPIData() method is executing after the numberOfRowsInSection() is called. So, the table is rendered empty.

How do I call the getAPIData() before table is loaded on screen?

Upvotes: 0

Views: 191

Answers (2)

Jordan Bonitatis
Jordan Bonitatis

Reputation: 1547

I believe the problem here is that NSURLSession dataTaskWithURL is asynchronous.

I think you could continue to use an asynchronous method and call [self.tableView reloadData]; after the call returns successfully (e.g., in your completion handler). You could display an activity indicator while you wait for the load to complete.

Or you could make a blocking, synchronous request like so:

// define the URL
NSURL url = [NSURL URLWithString: @"https://api.edmunds.com/api/dealer/v2/dealers?zipcode=%@&radius=%@&fmt=json&api_key=ycwedw68qast829zx7sn9jnq"];

// attempt the request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                    cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
                                                    timeoutInterval:10];
[request setHTTPMethod: @"GET"];

NSError *reqError;
NSURLResponse *urlResponse;
NSData *returnedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&reqError];

// parse `returnedData` here

Now you will have your NSData object and you can parse it here the same way you were doing in your completionHandler. This option is viable if you trust that your request response will return quickly.

Final option: use NSURLConnection to perform an async request and use its - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data delegate method to update a UIProgressView for more precise indicator of activity. I would encourage you to look into this method if your request response time is long enough to make the user wonder if anything is happening (e.g., more than a few seconds).

Upvotes: 0

Duncan C
Duncan C

Reputation: 131481

Short answer: You don't. You display an empty table view, and then in the completion block, you call the tableView's reloadData method and THEN it loads its contents.

Upvotes: 8

Related Questions