10

我使用异步块(大中央调度)来加载我的单元格图像。但是,如果您快速滚动,它们仍然会出现,但速度非常快,直到它加载了正确的。我确定这是一个常见问题,但我似乎找不到解决办法。

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


// Load the image with an GCD block executed in another thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[[appDelegate offersFeeds] objectAtIndex:indexPath.row] imageurl]]];

    dispatch_async(dispatch_get_main_queue(), ^{

        UIImage *offersImage = [UIImage imageWithData:data];

        cell.imageView.image = offersImage;
    });
});

cell.textLabel.text = [[[appDelegate offersFeeds] objectAtIndex:indexPath.row] title];
cell.detailTextLabel.text = [[[appDelegate offersFeeds] objectAtIndex:indexPath.row] subtitle];

return cell;
}
4

4 回答 4

18

至少,您可能希望在您之前从单元格中删除图像(如果它是重复使用的单元格)dispatch_async

cell.imageView.image = [UIImage imageNamed:@"placeholder.png"];

或者

cell.imageView.image = nil;

您还想确保在更新之前有问题的单元格仍然在屏幕上(通过使用UITableView方法,如果该行的单元格不再可见,则cellForRowAtIndexPath:返回,不要与方法混淆),例如:nilUITableViewDataDelegatetableView:cellForRowAtIndexPath:

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

cell.imageView.image = [UIImage imageNamed:@"placeholder.png"];

// Load the image with an GCD block executed in another thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[[appDelegate offersFeeds] objectAtIndex:indexPath.row] imageurl]]];

    if (data) {
        UIImage *offersImage = [UIImage imageWithData:data];
        if (offersImage) {
            dispatch_async(dispatch_get_main_queue(), ^{
                UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];

                if (updateCell) {
                    updateCell.imageView.image = offersImage;
                }
            });
        }
    }
});

cell.textLabel.text = [[[appDelegate offersFeeds] objectAtIndex:indexPath.row] title];
cell.detailTextLabel.text = [[[appDelegate offersFeeds] objectAtIndex:indexPath.row] subtitle];

return cell;

坦率地说,您还应该使用缓存来避免不必要地重新检索图像(例如,您向下滚动一点然后向上滚动,您不想为那些先前单元格的图像发出网络请求)。更好的是,您应该使用其中一种UIImageView类别(例如SDWebImageAFNetworking中包含的类别)。这实现了异步图像加载,但也优雅地处理缓存(不要重新检索几秒钟前刚刚检索的图像),取消尚未发生的图像(例如,如果用户快速滚动到第 100 行,你可能不'不想在向用户显示第 100 行的图像之前等待前 99 个检索)。

于 2013-10-30T18:23:33.313 回答
2

这是异步图像加载的问题......假设您在任何给定时间都有 5 个可见行。如果您快速滚动,并且向下滚动例如 10 行,tableView:cellForRowAtIndexPath则会调用 10 次。问题是这些调用比返回图像要快,并且您有来自不同 URL 的 10 个待处理图像。当图像最终从服务器返回时,它们将在您放入异步加载器中的那些单元格上返回。由于您只重用了 5 个单元格,因此其中一些图像将在每个单元格上显示两次,因为它们是从服务器下载的,这就是您看到闪烁的原因。还有记得打电话

cell.imageView.image = nil

在调用异步下载方法之前,因为重用单元格中的前一个图像将保留,并且在分配新图像时也会导致闪烁效果。

解决此问题的方法是存储您必须在每个单元格上显示的图像的最新 URL,然后当图像从服务器返回时,将该 URL 与您在请求中的 URL 进行检查。如果不相同,请缓存该图像以备后用。对于缓存请求,请查看NSURLRequestNSURLConnection类。

我强烈建议您使用AFNetworking进行任何服务器通信。

祝你好运!

于 2013-10-30T18:55:57.973 回答
2

您闪烁的原因是您在滚动期间开始下载多个图像,每次您在屏幕上显示一个单元格时都会执行一个新请求,并且可能没有完成旧请求,每个平铺请求都会完成图像是在单元格上设置的,所以如果你快速滚动,你会使用假设一个单元格 3 次 = 3 个将被触发的请求 = 3 个图像将被设置在该单元格上 = 闪烁。

我遇到了同样的问题,这是我的方法:创建一个包含所有必需视图的自定义单元格。每个单元格都有自己的下载操作。在单元格的-prepareForReuse方法中。我会将图像设为 nil 并取消请求。

这样,对于每个单元格,我只有一个请求操作 = 一个图像 = 没有闪烁。

AFNetworking如果您不取消图像下载,即使使用也会遇到同样的问题。

于 2013-10-30T19:15:09.420 回答
0

问题是您在主线程上下载图像。为此调度一个后台队列:

dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);

    // execute a task on that queue asynchronously
    dispatch_async(myQueue, ^{
      NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[[appDelegate offersFeeds] objectAtIndex:indexPath.row] imageurl]]];
//UI updates should remain on the main thread
UIImage *offersImage = [UIImage imageWithData:data];
    dispatch_async(dispatch_get_main_queue(), ^{

        UIImage *offersImage = [UIImage imageWithData:data];

        cell.imageView.image = offersImage;
    });
    });
于 2013-10-30T18:27:29.800 回答