UITableView中的图像在滚动时不断重新加载和错误的图像闪烁

时间:2014-11-06 09:07:11

标签: ios objective-c xcode uitableview ios8

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

来提取Feed
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;

6 个答案:

答案 0 :(得分:0)

你的代码缺少一行,我添加了。

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;

答案 1 :(得分:0)

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

细胞0
单元1
...
细胞9

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

块0 - >单元格0 块1 - >单元1
...
方框9 - >细胞9

如果您不滚动直到所有10次下载完成,这将正常工作。

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

首先,它可以重用Cell 0并创建块10 - > Cell 0。

如果在选择单元格0以供重复使用时块0未完成,则现在将有两个块想要将它们的图像放在同一单元格上。 导致以下两种情况:

  1. 块0先完成,然后块10
  2. 块10首先完成,然后块0
  3. 这是导致"闪烁"。

    的原因

    然后想象在几秒钟内滚动1000个单元格:)

    <强>解决方案

    您需要能够取消已重复使用的单元格的排队块。

    我会使用例如SDWebImageFastImageCache

答案 2 :(得分:0)

你怎么说。你在另一个线程中捕获图像,以防止冻结。并且在tableView中,单元格被重用,而在一个后台线程中,您正在捕获新照片,在主线程中返回包含上一张照片的单元格。 在代码中我修复了它并提供了更好的解释:

customCell.customCellTextLabel.text = [NSString stringWithFormat:@&#34;%@&#34;,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;

答案 3 :(得分:0)

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

答案 4 :(得分:0)

每次重新下载图像时滚动表格。为了防止这种情况,我更喜欢你从缓存中获取图像并直接在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];
        });
    });

也许这会对你有帮助。

答案 5 :(得分:0)

您应该考虑使用此库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;
}