Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My Grand Central Dispatch usage: Am I using it correctly?

I am fetching data from a server in JSON format. It's only about 150 records and I was not using GCD initially but every now and again when I hit the button in the app to view the table with data it would delay for about a couple of seconds before switching to the table view and displaying the data. So I implemented GCD and now when I hit the button it switches to the tableview immediately but then there is a few seconds delay in loading the data, which seems longer than the pre-GCD implementation. So I'm not sure if I am using GCD correctly, or if it's my server causing the delay (which I think is the culprit). Here is the implementation of GCD in a method called retrieveData which I call in viewDidLoad as [self retrieveData]:

- (void)retrieveData
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

        NSURL *url = [NSURL URLWithString:@"http://MY_URL/JSON/document.json"];
        NSData * data = [NSData dataWithContentsOfURL:url];

        dispatch_async(dispatch_get_main_queue(), ^{

    json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

    //Set up our exhibitors array
    exhibitorsArray = [[NSMutableArray alloc] init];

    for (int i = 0; i < json.count; i++) {
        //create exhibitors object
        NSString * blabel = [[json objectAtIndex:i] objectForKey:@"BoothLabel"];
        NSString * bName = [[json objectAtIndex:i] objectForKey:@"Name"];
        NSString * bURL = [[json objectAtIndex:i] objectForKey:@"HyperLnkFldVal"];


        exhibitors * myExhibitors = [[exhibitors alloc] initWithBoothName: bName   andboothLabel: blabel andBoothURL: bURL];

        //Add our exhibitors object to our exhibitorsArray
        [exhibitorsArray addObject:myExhibitors];

        //Sort by name
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
        [exhibitorsArray sortUsingDescriptors:[NSMutableArray arrayWithObject:sort]];

    }

    [self.myTableView reloadData];

        });
    });

}
like image 413
bachma0507 Avatar asked Jan 21 '26 16:01

bachma0507


1 Answers

This is basically correct. Dispatch the data retrieval to the background queue, and then dispatch the model and UI update back to the main queue. Well done.

In terms of its being slower, I don't see anything there that would account for that. GCD introduces some overhead, but generally not observable. It may be a bit of a "watched kettle never boils" issue.

A couple of unrelated thoughts, though:

  1. I might suggest moving the sort to outside of the for loop, but before the reloadData. You're sorting it 150 times. If doing an insertion sort, you could do it within the loop, but I don't think that's happening here. I'd move the sort to the end of the loop. I'm not sure if the performance gain will be observable, but there should be some modest improvement.

  2. You might want to make sure data is not nil (e.g. no network, or some other network issue), because if it is, JSONObjectWithData will crash.

  3. Your json object is an external variable. It should probably be a local variable of your retrieveData method. There's no need to make it an instance variable. It's cleaner to make it a local variable if appropriate.

  4. You probably should adopt the naming convention whereby class names start with uppercase letters (e.g. Exhibitor instead of exhibitors).

  5. Very minor point, but your blabel variable should probably be bLabel. Even better, I might rename these three variables boothLabel, boothName, and boothUrlString.

  6. You're using instance variable for exhibitorsArray. I presume you're doing this elsewhere, too. You might want to consider using declared properties instead.

  7. You might want to turn on the network activity indicator before dispatching your code to the background, and turning it back off when you perform reloadData.

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    
  8. If you wanted to get really sophisticated, you might reconsider whether you want to use GCD's global queues (because if you refresh 10 times quickly, all ten will run, whereas you probably only want the last one to run). This is a more complicated topic, so I won't cover that here, but if you're interested, you might want to refer to the discussion of operation queues the Concurrency Programming Guide, in which you can create operations that are cancelable (and thus, when initiating a new operation, cancel the prior one(s)).

    You might also want to refer to the Building Concurrent User Interfaces on iOS WWDC 2012 video.

But this is all tangential to your original question: Yes, you have tackled this appropriately.

like image 84
Rob Avatar answered Jan 24 '26 07:01

Rob