ios – 如何获得许多图像的快速UICollectionView(50-200)?

前端之家收集整理的这篇文章主要介绍了ios – 如何获得许多图像的快速UICollectionView(50-200)?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用UICollectionView在一个应用程序中显示相当多的照片(50-200),我有问题让它变得快乐(例如像照片应用程序).

我有一个自定义UICollectionViewCell与UIImageView作为子视图.我正在使用UIImage.imageWithContentsOfFile :,将文件系统中的图像加载到单元格内的UIImageView中.

我现在已经尝试了很多方法,但是它们已经是bug或者性能问题.

注意:我使用RubyMotion,所以我将使用Ruby样式编写任何代码片段.

首先,这是我的自定义UICollectionViewCell类来引用…

class CustomCell < UICollectionViewCell
  def initWithFrame(rect)
    super

    @image_view = UIImageView.alloc.initWithFrame(self.bounds).tap do |iv|
      iv.contentMode = UIViewContentModeScaleAspectFill
      iv.clipsToBounds = true
      iv.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth
      self.contentView.addSubview(iv)
    end

    self
  end

  def prepareForReuse
    super
    @image_view.image = nil
  end

  def image=(image)
    @image_view.image = image
  end
end

方法#1

保持简单

def collectionView(collection_view,cellForItemAtIndexPath: index_path)
  cell = collection_view.dequeueReusableCellWithReuseIdentifier(CELL_IDENTIFIER,forIndexPath: index_path)
  image_path = @image_paths[index_path.row]
  cell.image = UIImage.imageWithContentsOfFile(image_path)
end

使用此向上/向下滚动是可怕的.这是跳跃和缓慢.

方法#2

通过NSCache添加一些缓存…

def viewDidLoad
  ...
  @images_cache = NSCache.alloc.init
  ...
end

def collectionView(collection_view,forIndexPath: index_path)
  image_path = @image_paths[index_path.row]

  if cached_image = @images_cache.objectForKey(image_path)
    cell.image = cached_image
  else
    image = UIImage.imageWithContentsOfFile(image_path)
    @images_cache.setObject(image,forKey: image_path)
    cell.image = image
  end
end

再次,第一个完整的滚动跳跃和缓慢,但从那以后,它是顺利的航行.

方法#3

加载图像异步…(并保持缓存)

def viewDidLoad
  ...
  @images_cache = NSCache.alloc.init
  @image_loading_queue = NSOperationQueue.alloc.init
  @image_loading_queue.maxConcurrentOperationCount = 3
  ...
end

def collectionView(collection_view,forIndexPath: index_path)
  image_path = @image_paths[index_path.row]

  if cached_image = @images_cache.objectForKey(image_path)
    cell.image = cached_image
  else
    @operation = NSBlockOperation.blockOperationWithBlock lambda {
      @image = UIImage.imageWithContentsOfFile(image_path)
      Dispatch::Queue.main.async do
        return unless collectionView.indexPathsForVisibleItems.containsObject(index_path)
        @images_cache.setObject(@image,forKey: image_path)
        cell = collectionView.cellForItemAtIndexPath(index_path)
        cell.image = @image
      end
    }
    @image_loading_queue.addOperation(@operation)
  end
end

这看起来很有希望,但是有一个我无法追踪的错误.在初始视图加载时,所有图像都是相同的图像,当您滚动整个块加载与另一个图像,但都具有该图像.我试过调试,但我无法想像出来.

我也尝试用Dispatch :: Queue.concurrent.async {…}替换NSOperation,但是似乎是一样的.

我认为这可能是正确的方法,如果我能让它正常工作.

方法#4

在沮丧中,我决定将所有图像预先加载为UIImages …

def viewDidLoad
  ...
  @preloaded_images = @image_paths.map do |path|
    UIImage.imageWithContentsOfFile(path)
  end
  ...
end

def collectionView(collection_view,forIndexPath: index_path)
  cell.image = @preloaded_images[index_path.row]
end

在第一个完整的卷轴中,结果变得有点慢,跳跃,但一切顺利.

概要

所以,如果有人能指出我正确的方向,我会非常感激.照片应用程序如何做得很好?

注意其他人:[被接受]的答案解决了我的图像出现在错误的单元格的问题,但即使在调整我的图像大小以正确的大小后,我仍然正在滚动滚动.在将我的代码剥离到裸机之后,我最终发现UIImage#imageWithContentsOfFile是罪魁祸首.即使我使用这种方法预热了UIImages的缓存,UIImage似乎在内部做一些懒惰的缓存.更新我的缓存加温代码以使用这里详细说明的解决方案 – stackoverflow.com/a/10664707/71810 – 我终于有超级光滑〜60FPS滚动.

解决方法

我认为#3方法是最好的方法,我想我可能会发现这个bug.

您在操作块中为@image分配整个集合视图类的私有变量.你应该改变:

@image = UIImage.imageWithContentsOfFile(image_path)

image = UIImage.imageWithContentsOfFile(image_path)

并更改@image的所有引用以使用局部变量.我愿意打赌,问题是每次创建一个操作块并分配给实例变量时,你正在替换已经存在的内容.由于操作块出现的一些随机性,主队列异步回调正在获得相同的图像,因为它正在访问最后一次@image被分配.

本质上,@image像操作和异步回调块的全局变量一样.

猜你在找的iOS相关文章