1

I'd like to find out the reasons why my application is slow. Here's what my view controller is doing:

  1. (viewDidLoad) Retrieves data from a webservice with AFNetworking.
  2. Parses the response, creates custom objects and saves them in a dictionary.
  3. Reloads tableview data to fill it with the custom objects.

My AFNetworking call:

NSString *url = [Utils urlForObjectType:objectGames];

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFJSONRequestSerializer *requestSerializer = [AFJSONRequestSerializer serializer];
[requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
manager.requestSerializer = requestSerializer;
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    [self didReceiveGames:operation.responseData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

TableView Methods:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *identifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (cell == nil)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault  reuseIdentifier:identifier];


        NSString *competition = [competitionNames objectAtIndex:indexPath.section];
        NSArray *competitionGames = [competitions objectForKey:competition];
        Game *game = [competitionGames objectAtIndex:indexPath.row];

        Team *teamA = [game teamA];
        Team *teamB = [game teamB];

        UILabel *labelTeamA = (UILabel *)[cell viewWithTag:100];
        UILabel *labelTeamB = (UILabel *)[cell viewWithTag:101];
        UILabel *labelResultA = (UILabel *)[cell viewWithTag:102];
        [labelResultA setText:nil];
        UILabel *labelResultB = (UILabel *)[cell viewWithTag:103];
        [labelResultB setText:nil];
        UIImageView *imageTeamA = (UIImageView *)[cell viewWithTag:104];
        UIImageView *imageTeamB = (UIImageView *)[cell viewWithTag:105];

        UILabel *labelState = (UILabel *)[cell viewWithTag:106];
        [labelState setText:nil];

        GameState state = [game state];

        NSString *urlImageA = [Utils urlForObjectType:objectTeamImage andID:[teamA teamID]];
        NSString *urlImageB = [Utils urlForObjectType:objectTeamImage andID:[teamB teamID]];

        /* Time Background */
        UIImageView *timeBackground = (UIImageView *) [cell viewWithTag:107];
        [timeBackground setHidden:NO];

        [cell setBackgroundColor:[UIColor clearColor]];

            switch (state) {
                case statePlayed: {
                    [labelResultA setText:[NSString stringWithFormat:@"%d", [game finalResultA]]];
                    [labelResultB setText:[NSString stringWithFormat:@"%d", [game finalResultB]]];
                    [timeBackground setHidden:YES];
                }

                    break;
                case stateFixture: {
                    /* Set labelState to hours */
                    NSDate *date = [game date];
                    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear | NSCalendarUnitHour | NSCalendarUnitMinute fromDate:date];

                    NSString *minutes;
                    if ([components minute] == 0) {
                        minutes = @"00";
                    } else {
                        minutes = [NSString stringWithFormat:@"%d", [components minute]];
                    }
                    [labelState setText:[NSString stringWithFormat:@"%dh%@", [components hour], minutes]];
                }
                    break;
                case stateCancelled:
                    [labelState setText:@"CANCELLED"];
                    break;
                case statePlaying: {
                    [labelResultA setText:[NSString stringWithFormat:@"%d", [game finalResultA]]];
                    [labelResultB setText:[NSString stringWithFormat:@"%d", [game finalResultB]]];
                    [timeBackground setHidden:YES];
                }
                    break;
                case statePostponed:
                    [labelState setText:@"POSTPONED"];
                    break;
                case stateSuspended:
                    [labelState setText:@"SUSPENSED"];
                    break;
                default:
                    break;
            }

            [labelTeamA setText:[teamA name]];
            [labelTeamB setText:[teamB name]];
            [imageTeamA setImageWithURL:[NSURL URLWithString:urlImageA]];
            [imageTeamB setImageWithURL:[NSURL URLWithString:urlImageB]];

    return cell;

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSArray *competitionGames = [competitions objectForKey:[competitionNames objectAtIndex:section]];
    return [competitionGames count];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [competitionNames count];
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    UIView *header = [[NSBundle mainBundle] loadNibNamed:@"GamesHeaderIPAD" owner:self options:nil][0];

    NSString *competitionName = [[competitionNames objectAtIndex:section] uppercaseString];

    UILabel *labelCompetition = (UILabel *)[header viewWithTag:100];
    [labelCompetition setText:competitionName];

    return header;
}

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 42;
}

EDIT: It has nothing to do with AFNetworking, I just saved the response in NSUserDefaults, read it from there and it is still slow.

Thanks

diogo.appDev
  • 1,595
  • 5
  • 16
  • 30

3 Answers3

0

Make the webservice call in another thread.

Personally, I like to use Grand Central dispatch. This question using dispatch_sync in Grand Central Dispatch shows some good syntax. You place everything to run in the background in the dispatch_async part, when the service has got it's data you can update/reload your tableview safely in the dispatch_sync part.

Community
  • 1
  • 1
Adam Knights
  • 2,141
  • 1
  • 25
  • 48
0

You can use this method for background processing:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSString *url = [Utils urlForObjectType:objectGames];

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    AFJSONRequestSerializer *requestSerializer = [AFJSONRequestSerializer serializer];
    [requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    manager.requestSerializer = requestSerializer;
    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation,id responseObject) {
        dispatch_async(dispatch_get_main_queue(), ^{
           [self didReceiveGames:operation.responseData];
        }];
    }     
    failure:^(AFHTTPRequestOperation *operation, NSError *error) {

         dispatch_async(dispatch_get_main_queue(), ^{
           [self didReceiveGames:operation.responseData];
        }];
    NSLog(@"Error: %@", error);
       }];
    });
Norbert
  • 4,239
  • 7
  • 37
  • 59
hmdeep
  • 2,910
  • 3
  • 14
  • 22
0

The first step in speeding up in that case is replacing viewWithTag with IBOutlets.

Nikita Took
  • 3,980
  • 25
  • 33