繁体   English   中英

UITableView中的图像保持重新加载,并且滚动时错误的图像闪烁

[英]Images in UITableView keep re-loading and wrong images flash while scrolling

我创建了一个UITableView,它填充来自URL请求的每个单元格。 我已经使用'dispatch_queue'来防止UItableView冻结。 出于某种原因,当我滚动浏览UITableView时,图像会闪烁并消失,并在错误的单元格中填充一秒钟,直到修复自身。 这是我的代码。 我正在使用restkit提取提要

customCell.customCellTextLabel.text = [NSString stringWithFormat:@"%@",feedO.title];

    NSString *string = [NSString stringWithFormat:@"%@",feedO.body];

    NSURL *urlString;

        NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
        NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
        for (NSTextCheckingResult *match in matches) {
            if ([match resultType] == NSTextCheckingTypeLink) {
                urlString = [match URL];
                NSLog(@"found Body URL: %@ and title %@", urlString,feedO.title);
            }
        }

        dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
        dispatch_async(imageQueue, ^{

            NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];

            dispatch_async(dispatch_get_main_queue(), ^{

                customCell.customCellImageView.image = [UIImage imageWithData: data];
            });
        });


    return customCell;

您添加的代码缺少一行。

customCell.customCellImageView.image = nil;

customCell.customCellTextLabel.text = [NSString stringWithFormat:@"%@",feedO.title];

NSString *string = [NSString stringWithFormat:@"%@",feedO.body];

NSURL *urlString;
customCell.customCellImageView.image =nil;

    NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
    NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
    for (NSTextCheckingResult *match in matches) {
        if ([match resultType] == NSTextCheckingTypeLink) {
            urlString = [match URL];
            NSLog(@"found Body URL: %@ and title %@", urlString,feedO.title);
        }
    }

    dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
    dispatch_async(imageQueue, ^{

        NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];

        dispatch_async(dispatch_get_main_queue(), ^{

            customCell.customCellImageView.image = [UIImage imageWithData: data];
        });
    });


return customCell;

原因是UITableView正在重用创建的单元格。 因此,它首先创建了CustomCell类的10个。

储存格0
单元格1
...
单元格9

通过创建这10个单元,它将启动10个异步调用以获取图像。

块0->单元0
块1->单元1
...
块9->单元9

如果在所有10个下载完成之前不滚动,则此方法会正常工作。

但是,一旦您开始滚动, UITableView将开始重新使用创建的单元格并启动新的下载。

因此,它首先可以重用单元0并创建块10->单元0。

如果在选择单元0进行重用时块0尚未完成,那么您现在将有两个块想要将其图像放置在同一单元上。 导致以下两种情况:

  1. 块0首先完成,然后块10
  2. 块10首先完成,然后块0

这就是导致“闪烁”的原因。

然后想象一下在几秒钟内滚动浏览数千个单元格:)

您需要能够取消排队的块,以便重新使用您的单元格。

我会使用例如SDWebImageFastImageCache

你怎么说 您将图像捕获在另一个线程中,以防止冻结。 在tableView中,单元被重用,而在一个后台线程中捕获新照片时,在主线程中,返回具有前一张照片的单元。 在代码中,我对其进行了修复并提供了更好的解释:

customCell.customCellTextLabel.text = [NSString stringWithFormat:@“%@”,feedO.title];

NSString *string = [NSString stringWithFormat:@"%@",feedO.body];

NSURL *urlString;

    NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
    NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
    for (NSTextCheckingResult *match in matches) {
        if ([match resultType] == NSTextCheckingTypeLink) {
            urlString = [match URL];
            NSLog(@"found Body URL: %@ and title %@", urlString,feedO.title);
        }
    }
   // Here you need, at least quit the previous imagen, is better if you implement
   //   and activity indicator (here start), and also you should implement some imagen cache.
   customCell.customCellImageView.image = nil;


   // Apart from here, go to another thread.

    dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
    dispatch_async(imageQueue, ^{

        // this operation is slowly that return a cell, this happens after [1]
        NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];

        dispatch_async(dispatch_get_main_queue(), ^{

        //If you implement and activity indicator stop here.
            customCell.customCellImageView.image = [UIImage imageWithData: data];
        });
    });

// [1] the cell is returned before the image is ready.
return customCell;

以上答案是正确的。 但无需下载单元格中的图像即可。 您可以在符合您要求的viewWillAppear或ViewDidLoad中进行表加载之前下载图像。

每次滚动表格时,图像都会再次下载。 为了防止这种情况,我更希望您从缓存中获取图像并直接在imageview中进行设置。 因此根据您的代码。 如果从0索引滚动到10,则单元格将下载所有10个单元格的图像。 之后,如果再次滚动10到索引0。 然后图像将再次下载。

您可以使用( https://github.com/rs/SDWebImage )下载图像异步。 它非常容易和快速。

我更喜欢这个库,因为它将处理您的缓存。 只需写下面的代码

#import "UIImageView+WebCache.h"

// in cellForRowAtIndexPath.
[customCell.customCellImageView sd_setImageWithURL: [NSURL URLWithString:urlString]];

删除下面的代码。

dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
    dispatch_async(imageQueue, ^{

        NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];

        dispatch_async(dispatch_get_main_queue(), ^{

            customCell.customCellImageView.image = [UIImage imageWithData: data];
        });
    });

也许这会对您有所帮助。

您应该考虑使用此库SDWebImage,有关此类问题,请参见https://github.com/rs/SDWebImage 它非常轻松地处理远程图像的异步下载和缓存。

最简单的安装通过使用CocoaPods完成

CocoaPods( http://cocoapods.org )是Objective-C的依赖项管理器,它可以自动化并简化在项目中使用第三方库的过程。 有关更多详细信息,请参见“入门”部分。

在您的Podfile中使用

platform :ios, '6.1'
pod 'SDWebImage', '~>3.6'

安装SDWebImage的依赖项后,只需在视图控制器中使用以下几行:

#import <SDWebImage/UIImageView+WebCache.h>

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier] autorelease];
    }

    // Here we use the new provided setImageWithURL: method to load the web image
    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                   placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

    cell.textLabel.text = @"My Text";
    return cell;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM