0

I push a UIViewController on top of another and in its initwithNib I call a function that loads data from a MySQL database accessed over the internet. I store the results of a database query in an array and use data from that array to change a label on my view. Right now the view loads with "Put text here" in the view rather than the text I want to display. How can I make the view load only after the data is available?

Here's my init:

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

        if(self){
 ...setting additional irrelevant attributes....
            NSLog(@"running init");
           [self fetchFeed: 0]; <----here is where I grab the online data
            NSLog(@"%@ SELF TOTAL ARRAY", self.totalArray); <-here is where I try to print the data fetched, but actually this array is still empty when printed even though it's full later.

        }

Here's the function to get the data off the internet:

- (void)fetchFeed: (int) type
{
..code to set the request string....

    NSURL *url = [NSURL URLWithString:requestString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    /*

     NSURLSessionDataTask *dataTask =
     [self.session dataTaskWithRequest:req completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error){
*/


    static NSURLSession* sharedSessionMainQueue = nil;
    if(!sharedSessionMainQueue){
        sharedSessionMainQueue = [NSURLSession sessionWithConfiguration:nil delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
    }
    NSURLSessionDataTask *dataTask =
    [sharedSessionMainQueue dataTaskWithRequest:req completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error){
        NSMutableArray *jsonObject = [NSJSONSerialization JSONObjectWithData:data
                                                                      options:0
                                                                        error:nil];
         if(type<2) self.totalArray = jsonObject;

        // NSLog(@"json object is %@", jsonObject);
         dispatch_async(dispatch_get_main_queue(), ^{            
           [self updateDisplays];
         });

     }];
    [dataTask resume];
}

Here's the function I call inside the dispatch_async block to refresh the data once it's been loaded:

- (void)updateDisplays
{

    self.answerArray = [self.totalArray[self.indexLocal] objectForKey:@"answers"];
    self.answerIDArray = [self.totalArray[self.indexLocal] objectForKey:@"answerUser"];
    self.question.text = [self.totalArray[self.indexLocal] objectForKey:@"question"];
    self.questionUser.text = [self.totalArray[self.indexLocal] objectForKey:@"questionUser"];
//    NSLog(@"inside update displays");
}

As you can see, I started this using dispatch_async on the default queue then switched to the main queue thinking that would fix the lag, but it didn't. So how can I make the view wait for the data before it displays to the user? I have tried looking over the apple developer documentation for multithreading run loop management, but that seems like more than I need. What am I missing here?

For background, I took a look at some posts on synch vs. async tasks (Understanding dispatch_async) and on how to manage view latency in a uitable view while loading data from the internet (How to stop UITableView from loading until data has been fetched?). The suggestions in these (using the main queue or reloading data in the end of NSURLSession block) did not fix my problem.

Community
  • 1
  • 1

2 Answers2

1
  1. Have you considered deleting the text "Put text here" in your UILabel, or at least just setting the UILabel's text to an empty string?
  2. You could make an HTTP call for the data that you want in the parent view that pushes your UIViewController onto the navigation stack, and only present that view controller when you have the data. I would recommend adding some sort of loading indicator to your parent UI if you were going to go this route.
klein
  • 54
  • 6
0

So I found a better way to do this here: Loading screen for data-intensive view

You can spawn off a block of code to do what you want while you put on a loading screen. This better than staying on the old view and making the app look slow.

Community
  • 1
  • 1