自定义单元格图像在UITableView中自行更改

时间:2015-03-17 21:29:26

标签: ios uitableview

我有自定义单元格的表格视图。每个单元格都有图像,标题和描述。当我第一次加载表时,它加载正常。如果我慢慢滚动图像,也似乎工作正常。一旦我快速向下滚动(假设单元格的数量足够大而不适合而不向上和向下滚动),图像就会以随机顺序开始更改单元格。一些细胞具有相同的图像两次。

有什么理由发生这种情况?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    static NSString *CellIdentifier = @"Cell";
    BookmarkCellViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NewsArticle *currArt = [self.lN_Dept objectAtIndex:indexPath.row];

    if(currArt.artImage == Nil)
    {
        if([currArt.mainImage_URL rangeOfString:@"<img src="].location != NSNotFound)
        {
            NSRange range = [currArt.mainImage_URL rangeOfString:@"<img src=\"/CONC/"];
            NSString *substring = [[currArt.mainImage_URL substringFromIndex:NSMaxRange(range)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

            NSRange range2 = [substring rangeOfString:@"\""];
            NSString *substring2 = [[substring substringToIndex:NSMaxRange(range2)-1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

            NSString *imageURL = [PUB_URL stringByAppendingString:substring2];

            [self downloadImageWithURL:[NSURL URLWithString:imageURL] completionBlock:^(BOOL succeeded, UIImage *image) {
                if (succeeded) {
                    currArt.artImage = image;
                    cell.ArtDisplayImage.image = currArt.artImage;
                }
            }];
        }
    }
    else
    {
        cell.ArtDisplayImage.image = currArt.artImage;
    }
    [cell configureCellForEntry:currArticle];
    return cell;
}


- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *Data, NSError *error) {
                           if ( !error )
                           {
                               UIImage *image = [[UIImage alloc] initWithData:Data];
                               completionBlock(YES,image);
                           } else{
                               completionBlock(NO,nil);
                           }
                       }];
}

3 个答案:

答案 0 :(得分:2)

之所以发生这种情况,是因为您误解了UITableView的工作原理。让我们假设您的表视图有100个单元格,它可以同时显示10个单元格。加载表视图时,它会创建10个单元格实例。当您开始向下滚动表格视图时,它实际上不会创建单元格的新实例 - 重新使用从屏幕上消失的单元格(因为您正在调用[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];)。这意味着索引10处的单元格将具有与索引0处的单元格相同的参考 回到你的问题,你正在加载图像

[self downloadImageWithURL:[NSURL URLWithString:imageURL] completionBlock:^(BOOL succeeded, UIImage *image) {
            if (succeeded) {
                currArt.artImage = image;
                cell.ArtDisplayImage.image = currArt.artImage;
            }
}];

如果图像下载得更快,那么单元格会被重复使用(当你慢慢滚动时会发生这种情况)一切都会好起来的。但是如果在下载图像之前重新使用了单元格,那么内存中有两个块正在下载该单元格的图像。要解决此问题,我建议您使用SDWebImage自动处理这种情况,或取消下载从屏幕上消失的单元格的图像。希望这会有所帮助。

答案 1 :(得分:1)

这里可能存在竞争条件。下载排队等待给定的单元格,然后重新使用该单元格并设置另一个图像或下载排队,但是第一次下载完成并设置图像,即使单元格现在代表不同的元素。如果您想查看这确实是问题,请禁用单元重用(为每一行实例化一个新单元格)。如果问题消失了,那就是它。

您可以做的一件事是取消由给定单元格启动的现有下载(如果该单元格被重用)。查看以这种方式处理此问题的开源库SDWebImage

您可以做的另一件事是让单元格存储当前正在尝试加载的URL,并将结果下载的URL与单元格存储的URL进行比较,以查看它们是否仍然相同(并且仅设置图像,如果它们仍然相同)。

这样的事情应该这样做:

if(currArt.artImage == Nil)
{
    if([currArt.mainImage_URL rangeOfString:@"<img src="].location != NSNotFound)
    {
        NSRange range = [currArt.mainImage_URL rangeOfString:@"<img src=\"/CONC/"];
        NSString *substring = [[currArt.mainImage_URL substringFromIndex:NSMaxRange(range)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

        NSRange range2 = [substring rangeOfString:@"\""];
        NSString *substring2 = [[substring substringToIndex:NSMaxRange(range2)-1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

        NSString *imageURL = [PUB_URL stringByAppendingString:substring2];
        cell.imageURL = imageURL; // you need to add an imageURL string property to your cells
        // you need to return the URL string in your block to compare it
        [self downloadImageWithURL:[NSURL URLWithString:imageURL] completionBlock:^(BOOL succeeded, UIImage *image, NSString *url) 
        {
            if (succeeded) 
            {
                currArt.artImage = image;
                if(cell.imageURL isEqualToString:url])
                {
                    cell.ArtDisplayImage.image = currArt.artImage;
                }
            }
        }];
    }
}
else
{
    cell.ArtDisplayImage.image = currArt.artImage;
    cell.imageURL = nil; // make sure it is not overwritten
}

答案 2 :(得分:1)

这样的事情:

[self downloadImageWithURL:[NSURL URLWithString:imageURL] completionBlock:^(BOOL succeeded, UIImage *image) {
            if (succeeded) {

                YourCellType *cellToUpdate = [tableView cellForIndexPath:indexPath];
                if (cellToUpdate)
                {
                    currArt.artImage = image;
                    cellToUpdate.ArtDisplayImage.image = currArt.artImage;
                }
            }
        }];