0

So I have a UITableViewController in a UINavigationController as a view on a UITabBarController. So that aside, my UITableView has multiple sections and rows in each section and that works fine. In the last section, I set the cell.imageView.image property because I want a small picture on the side. Now the problem is, the above section sometimes (and randomly) shows the cell images when its not supposed to. I attached a screenshot of one of the upper sections that the cell should not have an image. Oh and in the code, I have an if statement that checks the cell section and if not last section, then set image view image to nil. screenshot

PFQuery *query = [PFQuery queryWithClassName:@"Riot_API"];
    query.limit = 1;
    [query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
        @autoreleasepool {
            NSString *champInfoURL = [NSString stringWithFormat:@"https://prod.api.pvp.net/api/lol/static-data/na/v1.2/champion/%d?champData=all&api_key=%@", [[[[content objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:@"championId"] intValue], object[@"key"]];
            NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:champInfoURL]];
            [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *champInfoData, NSError *connectionError) {
                @autoreleasepool {
                    NSURL *ddragonVersionURL = [[[NSURL URLWithString:@"http://ddragon.leagueoflegends.com/realms"] URLByAppendingPathComponent:[[NSUserDefaults standardUserDefaults] stringForKey:@"league_region"]] URLByAppendingPathExtension:@"json"];
                    NSURLRequest *ddragonVersionRequest = [NSURLRequest requestWithURL:ddragonVersionURL];
                    [NSURLConnection sendAsynchronousRequest:ddragonVersionRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *ddragonVersionResponse, NSData *ddragonVersionData, NSError *ddragonVersionConnectionError) {
                        if (!ddragonVersionConnectionError && ddragonVersionData) {
                            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
                                @autoreleasepool {
                                    NSDictionary *ddragonVersionDictionary = [[NSJSONSerialization JSONObjectWithData:ddragonVersionData options:kNilOptions error:nil] objectForKey:@"n"];
                                    NSURL *champIconServer = [NSURL URLWithString:[NSString stringWithFormat:@"http://ddragon.leagueoflegends.com/cdn/%@/img/champion", [ddragonVersionDictionary objectForKey:@"champion"]]];

                                    NSError *champInfoError;
                                    NSDictionary *champInfoJSON = [NSJSONSerialization JSONObjectWithData:champInfoData options:kNilOptions error:&champInfoError];
                                    NSDictionary *image = [champInfoJSON objectForKey:@"image"];

                                    NSURLRequest *champImageRequest = [NSURLRequest requestWithURL:[champIconServer URLByAppendingPathComponent:[image objectForKey:@"full"]]];

                                    [NSURLConnection sendAsynchronousRequest:champImageRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *imageData, NSError *connectionError) {
                                        if (imageData) {
                                            cell.imageView.image = [UIImage imageWithData:imageData];
                                            if (![self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
                                                if (indexPath.row == 0) {
                                                    @autoreleasepool {
                                                        CAShapeLayer *maskLayer = [CAShapeLayer layer];
                                                        maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:cell.imageView.bounds byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(5, 5)].CGPath;
                                                        cell.imageView.layer.mask = maskLayer;
                                                        cell.imageView.layer.masksToBounds = YES;
                                                    }
                                                } else if (indexPath.row == [[content objectAtIndex:indexPath.section] indexOfObject:[[content objectAtIndex:indexPath.section] lastObject]]) {
                                                    @autoreleasepool {
                                                        CAShapeLayer *maskLayer = [CAShapeLayer layer];
                                                        maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:cell.imageView.bounds byRoundingCorners:UIRectCornerBottomLeft cornerRadii:CGSizeMake(5, 5)].CGPath;
                                                        cell.imageView.layer.mask = maskLayer;
                                                        cell.imageView.layer.masksToBounds = YES;
                                                    }
                                                }
                                            }
                                            [cell setNeedsLayout];
                                        }
                                    }];
                                }
                            });
                        }
                    }];
                }
            }];
        }
    }];
} else {
    cell.textLabel.text = [[[content objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:@"name"];
    cell.textLabel.textColor = nil;
    cell.detailTextLabel.text = nil;
    cell.imageView.image = nil;
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
DemosJarco
  • 587
  • 4
  • 18
  • 6
    Wow, nested code like that is really horrible to read. If you really need to nest so many calls then at least do something like putting each separate call into its own method. That way each async call is on the first indent. – Fogmeister Jun 16 '14 at 16:16
  • 1
    Sounds like a cell reuse bug. – CrimsonChris Jun 16 '14 at 16:17

1 Answers1

3

OK, the problem here (apart from the code) is that the 4 network requests you have are going to take a long (indeterminate) amount of time.

Problem

When scrolling the table you will see a cell (say cell A) for a row (say row 4). The code will trigger and start a long chain of downloading things that will end up with an image. It will then take this image and stick it into cell A.

However, in the length of time it has taken to do this you have now scrolled to a new row (say row 20) and because of the way table view cells are queued. Row 20 is being displayed by Cell A.

So you have a problem. Cell A is now showing text for row 20 but the image for row 4.

This is why you are getting this problem.

Possible solution

The easiest solution would be to change your model o that the download doesn't go directly into the cell but instead goes into the model object (I think the Riot_API object maybe).

This way you can do something like this...

if (//riot object has image) {
    //show the image in the cell
} else {
    //tell the riot object to download its image
}

In the riot object you will have something like this...

- (void)downloadImage
{
    if (self.alreadyDownloading) {
        // you only need to download once
        return;
    }

    //start the downloading chain.

    //when it finishes you can tell the table view controller
    //maybe through delegation
    //that the download finished...

    [self.delegate riotObjectFinishedImageDownload:self];
}
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • well the 4 requests are as goes - 1) get my api key for connecting to Riot's server 2) get the name of the image file on the server 3) get the version of the image on the image server 4) download the actual image and place it in cell. So should I download the images too on the refresh method (where I get the text and other stuff for the cells) instead of on the cell load? – DemosJarco Jun 16 '14 at 18:02
  • @Fogmeister Can you please help me to solved this problems https://stackoverflow.com/q/46047271/2910061? – Ilesh P Sep 06 '17 at 00:10