【问题标题】:GCD UITableView asynchronous load images, wrong cells are loaded until new image downloadGCD UITableView 异步加载图片,加载错误的单元格,直到新图片下载
【发布时间】:2011-12-12 17:09:36
【问题描述】:

我有一个带有自定义单元格的 UITableView。我使用 Grand Central Dispatch 异步加载图像。一切正常,但是当我向下滚动时,会显示以前加载的图像,直到下载新图像。这是我的代码:

if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:@"image.png"]])
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,  0ul);
    dispatch_async(queue, ^{
        NSString *url=[pat stringByAppendingPathComponent:@"comments.txt"];
        NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
        NSURL *imageURL=[NSURL URLWithString:u];
        NSData *image=[NSData dataWithContentsOfURL:imageURL];
        [image writeToFile:[pat stringByAppendingPathComponent:@"image.png"] atomically:YES];
        dispatch_sync(dispatch_get_main_queue(), ^{
            cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:@"image.png"]];
            [cell setNeedsLayout];
            NSLog(@"Download");
        });
    });
}
else
{
    NSLog(@"cache");
    cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:@"image.png"]];
}

任何建议表示赞赏。 附言我重复使用细胞

【问题讨论】:

    标签: objective-c ios cocoa-touch uitableview


    【解决方案1】:

    您需要捕获索引路径而不是捕获单元格,然后使用以下方法获取单元格:

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    

    这样,如果单元格现在不在屏幕上,您将返回 nil 并且图像不会设置在错误的单元格上。

    您需要在dispatch_async() 之后添加的另一件事是cell.imageView.image=somePlaceholderImage

    例如:

    if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:@"image.png"]])
    {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,  0ul);
        dispatch_async(queue, ^{
            NSString *url=[pat stringByAppendingPathComponent:@"comments.txt"];
            NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
            NSURL *imageURL=[NSURL URLWithString:u];
            NSData *image=[NSData dataWithContentsOfURL:imageURL];
            [image writeToFile:[pat stringByAppendingPathComponent:@"image.png"] atomically:YES];
            dispatch_sync(dispatch_get_main_queue(), ^{
                UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:@"image.png"]];
                [cell setNeedsLayout];
                NSLog(@"Download");
            });
        });
        cell.imageView.image=[UIImage imageNamed:@"placeholder"];
    }
    else
    {
        NSLog(@"cache");
        cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:@"image.png"]];
    }
    

    【讨论】:

    • 感谢您的回复...但是,您能提供一些示例代码吗?
    【解决方案2】:

    在您的- (void)tableView:(UITableView *)aTableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { 中,您需要清除图像,或将其重置为您的微调器。由于表视图行被重用,这是您将看到的行为。

    【讨论】:

      【解决方案3】:

      UITableViewCell 没有为此目的定义 -(void) prepareForReuse 吗? 覆盖它并清除其中的 imageView。

      【讨论】:

      • 根据documentation,您不应该触摸prepareForReuse 中的内容。您应该重置 cellForRowAtIndexPath 中的内容。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多