【问题标题】:Loading images from Asset library to a UICollectionView将图片从资源库加载到 UICollectionView
【发布时间】:2014-09-16 07:33:26
【问题描述】:

我正在使用 ELCImagePicker https://github.com/B-Sides/ELCImagePickerController 从手机库中挑选我的图像。 ELC 有两个返回选项,第一个是 UIImage 本身(我不希望它在选择超过 5 个图像时由于内存而崩溃)。第二个是图像的资产位置,这对记忆很有好处,尽管我的问题是在集合视图上显示图像时。

所以我有这段代码可以正常工作并显示图像,但是当我在集合视图中上下滚动时,它会有点滞后。我认为这是因为每次它想要加载一个单元格时,它都必须经过一个块及其异步。我正在尝试找到一种方法来消除滞后并使其平滑滚动。

任何帮助将不胜感激。 :)

 ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

 [library assetForURL:_chosenImages[indexPath.row] resultBlock:^(ALAsset *asset) {

    UIImage *image = [UIImage imageWithCGImage:asset.thumbnail];
  // I believe the problem is here..
    [myCell.imageView setImage:image];
} failureBlock:^(NSError *error) {
    NSLog(@"An error occurred while loading image: %@", error.description);
}];

【问题讨论】:

  • 就我而言,当我处理这样的情况时。我在数组中使用了 ALAssets 而不是 AssetURL。将您的数据源更改为包含资产而不是 AssetURL。
  • 这会有什么不同?
  • 从某种意义上说,您不必每次都触发异步调用来获取资产,然后每次尝试在集合视图中显示单元格的图像。 [资产缩略图] 足够快,不会在您的主线程上造成延迟。
  • 我得到的东西看起来像这样: { UIImagePickerControllerMediaType = ALAssetTypePhoto; UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?id=1A255C21-88AB-4F62-83FA-D23547825C58&ext=JPG";这是我第一次使用资产,那么我如何才能真正从中获取资产呢?它被放置在一个 NSDictionary 中。
  • 见下面我的回答。一旦您修改了数据源以保存资产,然后在单元格显示方法中,删除异步调用以获取资产。只需使用索引路径然后缩略图获取资产。然后显示它。

标签: ios objective-c uiimageview uicollectionview


【解决方案1】:

ELCImagePickerController.m- (void)selectedAssets:(NSArray *)assets 方法中,您将能够看到这一行

ALAsset *asset = elcasset.asset;

在这一行之后,创建了一个字典,然后添加到returnArray。跳过这个字典创建部分。直接将资产添加到 returnArray。将 for 方法更改为如下所示:

for(ELCAsset *elcasset in assets) {
    ALAsset *asset = elcasset.asset;
    [returnArray addObject:asset];  
}

玩得开心。

***编辑*** 另外请创建一个单例来维护AssetLibraryELCAlbumPickerController 中的生命。

【讨论】:

  • 我试过这个解决方案,但不是只返回资产,而是返回字典中的资产(本质上是同一件事),尽管我遇到了另一个问题,如果我滚动,图像现在消失了,这是记录:在其拥有的 ALAssetsLibrary 的生命周期之后访问 的无效尝试..知道问题可能是什么吗?
  • 这意味着用于检索资产的 AssetLibrary self.library 已在ELCAlbumPickerController 中释放。检查它..
  • 那么解决方案又是,为 AssetLibrary 创建一个单例?
  • 它只在一个地方[[ALAssetsLibrary alloc] init]; 如果您无法保留资产库,您可以随时为AssetLibrary 创建一个单例。而且我想您将不得不这样做,因为我相信您稍后会使用这些资产来获得fullimages
  • 好的,我会这样做的。 :)
【解决方案2】:

首先,ALAssetsLibrary 不保证结果块在主线程上被调用。您应该在后台线程上执行昂贵的工作(生成UIImage),并且任何 UI 工作都应该在主线程上完成。所以你需要先解决这个问题:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    UIImage *image = [UIImage imageWithCGImage:asset.thumbnail];

    dispatch_async(dispatch_get_main_queue(), ^{
        [myCell.imageView setImage:image];
    });
});

其次,当您最终到达myCell 时,不再保证该单元格具有相同的内容。这是因为单元格在滚动期间被重用。所以你需要得到正确的单元格。

一种常见的方法是使用indexPath

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    UIImage *image = [UIImage imageWithCGImage:asset.thumbnail];

    dispatch_async(dispatch_get_main_queue(), ^{
        MyUICollectionViewCellSubclass *correctCell = (MyUICollectionViewCellSubclass *)[self.collectionView cellForItemAtIndexPath:indexPath];
        [correctCell.imageView setImage:image];
    });
});

但是,这仅在保证索引路径不会更改的情况下才有效,这取决于您的用例可能会或可能不会发生变化。例如,如果用户可以插入或删除项目,则您需要采用不同(但相似)的方法。

最后,确保在重复使用单元格时将nil 输出imageViewimage(这样在单元格滚动时不会显示旧图像。)


另外,我使用资产库已经有一段时间了,但我认为您不应该使用imageWithCGImage:,而应该使用imageWithCGImage:scale:orientation:。我相信您当前使用的方法在 Retina 设备上会显得模糊,并且可能会导致方向错误。

【讨论】:

  • 所以我已经完成了将它放在主线程中的第一部分,但是我无法初始化块内的单元格,因为 cellForItemAtIndexPath 应该返回该单元格。通过单独做第一部分,它似乎没有改变任何东西,它仍然滞后。另外,正如我所说,我确实正确获取了单元格,它在该特定单元格处返回了正确的图像,但需要一些时间来加载(这是问题所在):)
  • 我将按照我对上面 cmets 的回复方式进行回复,因为这是同样的问题。我得到的东西看起来像这样: { UIImagePickerControllerMediaType = ALAssetTypePhoto; UIImagePickerControllerReferenceURL = "assets-library://asset/asset.JPG?id=1A255C21-88AB-4F62-83FA-D23547825C58&ext=JP‌​G";这是我第一次使用资产,那么我如何才能真正从中获取资产呢?它被放置在一个 NSDictionary 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
  • 2011-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多