图像未立即在表格视图中加载

Posted

技术标签:

【中文标题】图像未立即在表格视图中加载【英文标题】:Image not loading immediately in Table View 【发布时间】:2013-07-04 18:55:38 【问题描述】:

我正在使用 SDWebImage 并从新闻 API 中获取与新闻文章相关联的图像。

问题是,在我开始滚动UITableView 之前,屏幕上的单元格的图像不会加载。一旦我滚动过一个单元格,它就会离开屏幕,一旦我回到它,图像最终会被加载。

这是我的 (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 代码:

if ([feedLocal.images count] == 0) 
    [cell.imageView setImage:[UIImage imageNamed:@"e.png"]];

else     
    Images *imageLocal = [feedLocal.images objectAtIndex:0];
    NSString *imageURL = [NSString stringWithFormat:@"%@", imageLocal.url];
    NSLog(@"img url: %@", imageURL);

    // Here we use the new provided setImageWithURL: method to load the web image
    __weak UITableViewCell *wcell = cell;
    [cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", imageURL]]
                   placeholderImage:[UIImage imageNamed:@"115_64.png"]
                          completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) 
                              if(image == nil) 
                                  [wcell.imageView setImage:[UIImage imageNamed:@"115_64.png"]];
                                   //];
                              
                          
    ];

知道为什么会这样吗?似乎当 UITableView 加载时,图像没有被告知加载或其他什么,直到滚动开始?

非常感谢任何建议,谢谢!

【问题讨论】:

这是令人耳目一新的问题。您必须进行 NSNotification 调用,并且在加载每个图像时,您必须调用 tableview 重新加载数据以便它立即显示图像 欣赏@AJ112 的评论...你有代码 sn-p 以便我可以看到我的代码中的样子吗?这是有道理的,但我以前从未这样做过,所以我想确保我正确地关注你。 在我的情况下,下载过程发生在不同的文件中,这就是我使用 NSNotificationCenter 的原因,但我遇到了完全相同的问题,即向下滚动时图像开始出现。你可以先调用 [self.tableView reloadData];在您下载图像并将其设置为您的图像视图之后。 我最初在我的viewDidLoad 中调用[_tableview reloadData]。但是当我出于某种原因尝试在cellForRowAtIndexPath 中调用它时,我一定找不到合适的位置,因为我无法让它刷新所有图像。 这和这个问题很相似:***.com/questions/9352638/… 解决方法是一样的;你的 UIImageView 有一个占位符。 【参考方案1】:

这将解决您的问题的可能性很小,但这太长了,无法放入评论:

提示 1:

如果您要重用单元格,则不应在回调中使用[wcell.imageView setImage:]。在执行回调代码时,wcell 将指向表格视图中与您要更改图像的单元格不同的单元格,这是一个非空的机会。

改为使用indexPath 来引用您要修改的单元格:

completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) 
    if(image == nil) 
        UITableViewCell *actualCell = [tableView cellForRowAtIndexPath:indexPath];
        [actualCell.imageView setImage:[UIImage imageNamed:@"115_64.png"]];
    

请注意,如果您要更改图像的单元格不再显示,cellForRowAtIndexPath: 将返回nil,这绝对没问题:

返回值

表示表格单元格的对象,如果单元格不可见或 indexPath 超出范围,则为 nil。

提示 2:

如果您已经有一个字符串,则无需重新创建一个字符串;)

[NSURL URLWithString:[NSString stringWithFormat:@"%@", imageURL]]

[NSURL URLWithString:imageURL] // imageURL is already a string

您的问题

我有点疑惑,你展示的代码真的是SDWebImage“how-to”示例的简单应用,我刚刚用框架的v3.3测试,我的单元格更新就好了.因此,请尽量减少代码以找出真正的问题。

我想说摆脱所有应用程序逻辑(例如feedLocal.images),然后找出问题是否真的来自SDWebImage

【讨论】:

感谢您抽出宝贵时间给予答复,非常感谢!我已经在我的项目中更改了提示 #2。部分问题是图像在模拟器中完美显示,但当我在我的设备上尝试时却没有。所以我发布的原始代码在模拟器中工作,但在我正在测试的实际 iPhone 上不起作用。有什么想法吗?【参考方案2】:

不确定您的问题是否已解决,但我通过以下代码解决了我的问题。

基本思想是在块内设置可用的单元格引用,并在完成方法中手动设置单元格的图像。希望对您有所帮助。

__block UITableViewCell *cell2 = cell;

id data = [[self itemArray] objectAtIndex:[indexPath item]];

if ([data isKindOfClass:[MyItems class]]) 

    MyItems *myData = (MyItems *)data;
    [[cell2 imageView] setImageWithURL:[myData url]
                      placeholderImage:[UIImage imageNamed:@"placeHolder.png"]
                             completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) 
                                 // do check that this is the right cell to put your image
                                 // your methods here

                                 if (image) 
                                     [[cell2 imageView] setImage:image];
                                 
    ];

为了检查这是否是正确的单元格,我想是这样的(我没有时间检查它)

__block UITableViewCell *cell2 = cell;

id data = [[self itemArray] objectAtIndex:[indexPath item]];

if ([data isKindOfClass:[MyItems class]]) 

    __block MyItems *myData = (MyItems *)data;
    [[cell2 imageView] setImageWithURL:[myData url]
                      placeholderImage:[UIImage imageNamed:@"placeHolder.png"]
                             completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) 
                                 // do check that this is the right cell to put your image
                                 // your methods here
                                 id currentData = [[self itemArray] objectAtIndex:[indexPath item]];
                                 if ([currentData isKindOfClass:[MyItems class]] && [ [[(MyItems *)currentData url] absoluteString] isEqualToString:[[myData url] absoluteString] ]) 
                                 // it is the right cell to put in :)
                                     if (image) 
                                         [[cell2 imageView] setImage:image];
                                     
                                 
    ];

【讨论】:

非常好,这是专门针对 SDWebImage 还是一般来说,这就是您的用途?再次感谢您的回复! 我写这个是为了和 SDWebImage 一起工作。一般来说,我永远不会喜欢写这个(如果你不从互联网上下载图像)。由于使用块引用必须小心内存和泄漏,我更喜欢将图像下载到模型(或某些文件系统),一旦完成,通知调用者(在这种情况下为 UITableView),更新单元图像。当然,您必须使用协议之类的东西,但是默认情况下使用 ARC 造成内存泄漏的可能性较小。【参考方案3】:

我之前遇到过类似的问题,结果发现 tableview 中的图像下载正确。您面临的真正问题是刷新问题。下载每个图像时,必须刷新它才能在 tableview 中显示。在我的例子中,下载部分是在一个单独的文件中完成的,所以我使用 NSNotificationCenter 告诉 tableview 控制器类刷新它。以下是您可以使用代码执行的操作:

if ([feedLocal.images count] == 0) 
    [cell.imageView setImage:[UIImage imageNamed:@"e.png"]];

else     
    Images *imageLocal = [feedLocal.images objectAtIndex:0];
    NSString *imageURL = [NSString stringWithFormat:@"%@", imageLocal.url];
    NSLog(@"img url: %@", imageURL);

    // Here we use the new provided setImageWithURL: method to load the web image
    __weak UITableViewCell *wcell = cell;
    [cell.imageView setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@", imageURL]]
                   placeholderImage:[UIImage imageNamed:@"115_64.png"]
                          completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) 
                              if(image == nil) 
                                  [wcell.imageView setImage:[UIImage imageNamed:@"115_64.png"]];
                                  [[NSNotificationCenter defaultCenter] postNotificationName:@"ImageDownloaded" object:nil];
                                   //];
                              
                          
    ];

然后您可以使用它调用重新加载数据,如下所示:

- (void) imageDownloaded:(NSNotification *)notification

    [self.tableView reloadData];

这样您无需滚动即可查看图片,而是在下载后立即显示。

希望这会有所帮助!

【讨论】:

亲爱的,我今晚试试看! 如何在 Swift 中使用完成的参数?【参考方案4】:
NSString *mainimg=[NSString stringWithFormat:@"%@",[[xmlDataDictionary valueForKeyPath:@"eg.main.img1"]objectAtIndex:indexPath.row]];
NSURL *url = [NSURL URLWithString:mainimg];
NSData *imge = [[NSData alloc] initWithContentsOfURL:url];
cell.img.image=[UIImage imageWithData:imge];

【讨论】:

此解决方案有效,但加载或滚动表格视图时设备出现延迟 我的表格单元格是动态的...如果您使用 AFNetworking,NSData 将消耗时间来加载通常在后台发生的图像。所以延迟

以上是关于图像未立即在表格视图中加载的主要内容,如果未能解决你的问题,请参考以下文章

集合视图未加载图像

图像下载后调整表格单元格大小

调用 layoutIfNeeded 后视图未立即显示

ios表格视图单元格按行索引顺序加载图像

单击表格视图单元格时加载缓慢

表格视图中的图像加载另一个几秒钟