SDWebImage repeating images in cell instead of wai

2019-03-02 19:28发布

问题:

I am using SDWebImage for fetching images from server to my table view app in IOS. But the problem is that when I scroll down in table view instead of waiting for the images to load it put the images downloaded in the first few rows of table view and repeat those images till the end row and when it downloads the images it changes those repeated images to the actual image for that row.

      NSURL * url = [NSURL URLWithString:string];

    SDWebImageManager *manager = [SDWebImageManager sharedManager];
    [manager downloadImageWithURL:url
                     options:0
                    progress:^(NSInteger receivedSize, NSInteger expectedSize)
     {
         // progression tracking code
     }
                   completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished,NSURL * url)
     {
         if (finished && image  )
         {

             NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
                 if ([visibleIndexPaths containsObject:indexPath]) {

                         cell.myImage.image = image;

                 }

         }

     }];

回答1:

Actually, it is not a bug with SDWebImage, but rather it's the nature of how UITableView works. downloadImageWithURL, is an async process,so when your tableView delegate/datasource methods are called, the image isn't downloaded yet, therefore cellForRow doesn't have an image to display. To overcome this issue you should first check image from cache as

[[SDWebImageManager sharedManager] diskImageExistsForURL:[NSURL URLWithString:ImageUrl]]

if yes then set image to UIImageView otherwise use downloadImageWithURL to download image and add cell tag(To display image to correct row) as

cell.tag = indexPath.row;

on successfull download first check correct row as

if(cell.tag == indexPath.row){

and set image to UIImageView.Here is setImage method.

-(void)setImage:(SLFirstTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath{
    SLFirstTableViewCellItem * slFirstTableViewCellItem = [self.categories objectAtIndex:indexPath.row]; // categories is array of items,replace with yours.

    NSString *ImageUrl = slFirstTableViewCellItem.imageUrl; //assume image url is in slFirstTableViewCellItem object.

    cell.tag = indexPath.row;

    if([[SDWebImageManager sharedManager] diskImageExistsForURL:[NSURL URLWithString:ImageUrl]]){
        [cell.imgItem setImage: [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:ImageUrl]];
        [self hideProgressView:cell];
    }else{
        [self showProgressView:cell];

        [SDWebImageDownloader.sharedDownloader downloadImageWithURL:[NSURL URLWithString:ImageUrl]
                                                            options:0
                                                           progress:^(NSInteger receivedSize, NSInteger expectedSize)
         {
             // progression tracking code
         }
                                                          completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
         {

             if (image && finished)
             {
                 [[SDImageCache sharedImageCache] storeImage:image forKey:ImageUrl]; // cache image

                 if(cell.tag == indexPath.row){ // check if correct row
                     [cell.imgItem setImage:image];
                     [self hideProgressView:cell];
                 }
             }else{
                 cell.imgItem.hidden = YES;
                 cell.progressBar.hidden = YES;
             }
         }];
    }
}

And define showProgressView and hideProgressView methods as

-(void)showProgressView:(SLFirstTableViewCell *)cell {
    cell.progressText.hidden = NO;
    cell.progressBar.hidden = NO;
    cell.imgItem.hidden = YES;
    [cell.progressBar startAnimating];
    [cell.progressText setText:@"Loading Image..."];
}

-(void)hideProgressView:(SLFirstTableViewCell *)cell{
    cell.progressBar.hidden = YES;
    cell.progressText.hidden = YES;
    cell.imgItem.hidden = NO;
    [cell.progressBar stopAnimating];
}

finally call setImage from cellForRowAtIndexPath method(before returning cell) as

[self setImage:cell atIndexPath:indexPath];