从 Document 目录加载多个图像时 UICollectionView 卡住

Posted

技术标签:

【中文标题】从 Document 目录加载多个图像时 UICollectionView 卡住【英文标题】:UICollectionView Stuck when loading multiple images from Document directory 【发布时间】:2018-08-07 10:21:58 【问题描述】:

我正在加载超过 30-50 张图像,这些图像存储在文档目录中。他们所有的图像都立即加载到collectionView,但是当滚动collectionView时它会卡住。

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

    static NSString *cellIdentifier = @"ImageCell";
    ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

    //Load image from document  directory
    NSString *imageName = [arrCollection objectAtIndex:indexPath.row];
    NSString *imagePath = [NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath, imageName];
    UIImage *localImg = [[UIImage alloc]initWithContentsOfFile:imagePath];

    cell.imgSketch.image = localImg;

    cell.txtName.text = [NSString stringWithFormat:@"%@",[imageName stringByReplacingOccurrencesOfString:@".png" withString:@""]];

    cell.layer.masksToBounds = YES;
    return cell;

我也尝试了以下调度块

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
                UIImage *localImg = [[UIImage alloc]initWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath,[arrCollection objectAtIndex:indexPath.row]]];
                dispatch_async(dispatch_get_main_queue(), ^
                    cell.imgSketch.image = localImg;
                );
            );

请建议我解决此问题的任何解决方案。

提前致谢

【问题讨论】:

可能是预取也可以帮助您解决以下问题 最好的解决方案是使用一些图像缓存库,如 SDWebImage,它非常易于使用,并且以异步方式加载和缓存图像。 github.com/rs/SDWebImage @vivekDas 我认为当我们想从 Web URL 加载图像时使用 SDWebImage 您可以尝试使用 imagePath 而不是 web url 来检查它是否有效。 @vivekDas [cell.imgSketch sd_setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath,[arrCollection objectAtIndex:indexPath.row]]]];这个我试过了,但是不行 【参考方案1】:

您可以使用SDWebImage 也可以显示文档目录中的图像。

[cell.imgSketch sd_setImageWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath,[arrCollection objectAtIndex:indexPath.row]]]];

注意:在创建NSURL 的对象时使用fileURLWithPath,因为它是文件的路径。

【讨论】:

如何删除缓存中的图片?我试过这个,但它不起作用[[SDImageCache sharedImageCache] removeImageForKey:[NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath,[arrCollection objectAtIndex:sender.tag]] fromDisk:YES withCompletion:nil]; @MonikaPatel 实际上这应该可以工作,代码看起来正确,你怎么知道图像没有从缓存中删除? 实际上我的应用程序只能在本地工作,现在用户可以将多个图像从图库导入到我的应用程序。所有图像名称都按此顺序 img1,img2,im3....n。现在的重点是,如果用户选择 3 张图片并在我的应用程序中导入所有 3 张图片。所以现在图像名称是分配 img1,img2,im3。现在用户删除这 3 个图像并导入新的 3 个图像。同样,图像名称将为 img1、img2、img3。所以这些 img1,img2,img3 图像从缓存中获取旧图像。它将显示已删除的旧图像,其中包含新的 3 张选定图像。 @MonikaPatel 您能否在清除所有图像的缓存后尝试一下,请查看此答案以获取更多详细信息***.com/a/39881690/6433023【参考方案2】:

我的建议是将您的图像加载操作移至后台线程。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^
   UIImage* localImage = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath,[arrCollection objectAtIndex:indexPath.row]]];    
   dispatch_async(dispatch_get_main_queue(), ^
      cell.imgSketch.image = localImage;
   );
);

【讨论】:

对不起,这个解决方案我已经试过了,但是不行。【参考方案3】:

我建议在cellForRowAt 中只加载一次所有图像

NSMutableArray*images; // every instance is of type UIImage not imageName

而不是这个

UIImage *localImg = [[UIImage alloc]initWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",(AppObj).imagefolderPath,[arrCollection objectAtIndex:indexPath.row]]];

注意:这个方法initWithContentsOfFile在mainQueue中运行所以是卡住的主要原因

【讨论】:

【参考方案4】:

如果我们使用大图像,collectionview/tableview 单元格会闪烁。尝试使用小尺寸图片或在后台队列中的cellForItemAtIndexPath 创建一张。

您可以通过在数组中缓存图像来提高性能。 注意:如果容量增加限制,请尝试清理它。

cell.imgSketch.image = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^

     UIImage *localImg = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", (AppObj).imagefolderPath, [arrCollection objectAtIndex:indexPath.row]]];

     NSData *imgData = UIImageJPEGRepresentation(localImg, 0.5);
     localImg = [UIImage imageWithData:imgData];

     dispatch_async(dispatch_get_main_queue(), ^
         ImageCell *imageCell = [collectionView cellForItemAtIndexPath:indexPath];
         if (imageCell) 
             cell.imgSketch.image = localImg;
         
    );
);

【讨论】:

您的代码很有帮助,但是当我滚动 collectionView 时,imageview 中的随机图像绑定和图像会在滚动过程中发生变化。 在从文件管理器加载之前设置cell.imgSketch.image = nil;

以上是关于从 Document 目录加载多个图像时 UICollectionView 卡住的主要内容,如果未能解决你的问题,请参考以下文章

使用swift从目录加载多个图像

从/在一个目录中加载/保存多个图像 - opencv c++

在 Objective C 中从 web 目录加载多个图像

将多个图像从本地 JSON 文件加载到 tableview 时 CFNetwork 内部错误

在 UIButtons 上从服务器加载多个图像?

无法从设备上的“文档”目录加载图像