【问题标题】:Custom Cell images are changing on their own in a UITableView [duplicate]自定义单元格图像在 UITableView 中自行更改 [重复]
【发布时间】:2015-03-17 21:29:26
【问题描述】:

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

知道为什么会这样吗?

- (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);
                           }
                       }];
}

【问题讨论】:

标签: ios uitableview


【解决方案1】:

这是因为您误解了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,它会自动处理这种情况,或者取消下载从屏幕上消失的单元格的图像。希望这会有所帮助。

【讨论】:

  • 您如何建议我取消下载从屏幕上消失的单元格的图像?
【解决方案2】:

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

您可以做的一件事是取消由给定单元开始的现有下载,如果该单元被重复使用。查看以这种方式处理此问题的开源库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
}

【讨论】:

  • 我在帖子中添加了另一个功能。你能告诉我如何修改它,让它按照你的建议去做。比较网址。谢谢
【解决方案3】:

所以是这样的:

[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;
                }
            }
        }];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多