- 然后在水平和垂直轴上进行计算,该计算基于期望的图片大小以及我们要渲染的像素和点大小:
let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scalelet downsampleOptions = [kCGImageSourceCreateThumbnailFromImageAlways: true,kCGImageSourceShouldCacheImmediately: true,kCGImageSourceCreateThumbnailWithTransform: true,kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
这里也创建了一个缩略图选项的字典,最重要的是 CacheImmediately 这个选项,通过这个选项,告诉 Core Graphics,当我们要求你创建缩略图时,这就是你应该为我创建解码缓冲区的确切时刻 。因此,我们可以确切的控制何时调用 CPU 来进行解码 。- 最后,我们创建缩略图,即拿到返回的 CGImage。
let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)
其完整代码如下:func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionarylet imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scalelet downsampleOptions = [kCGImageSourceCreateThumbnailFromImageAlways: true,kCGImageSourceShouldCacheImmediately: true,kCGImageSourceCreateThumbnailWithTransform: true,kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionarylet downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)return UIImage(cgImage: downsampledImage)}
在 UICollectionView 中的使用我们可能会在创建单元格时,直接使用下采样技术来生成的图片,代码如下:func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCollectionViewCellcell.layoutIfNeeded()let imageViewSize = cell.imageView.bounds.sizelet scale = collectionView.traitCollection.displayScalecell.imageView.image = downsample(imageAt: "", to: imageViewSize, scale: scale)}
这样确实会减少内存的使用量,但这并不能解决我们的另一个问题 。这些问题在可滚动的视图中是非常常见的 。当我们滚动页面时,CPU 相对比较空闲或它所做的工作可以在显示硬件需要帧缓冲的下一个副本之前完成,所以,当帧缓冲被更新时,我们能看到流畅的效果,并且显示硬件能及时获得新帧 。
但是,如果我们将显示另一行图像,将单元格交回 UICollectionView 之前,我们要求 core Graphics 解码这些图像,这将会花费很长的 CPU 时间,以至于我们不得不重新渲染帧缓冲区,但显示器硬件按固定的时间间隔运行,因此,从用户的角度来看,app 好像卡住了一样 。
这不仅会造成信息粘连,还会有明显的响应性后果,也对电池寿命有不利的影响 。
文章插图
我们可以使用两种技术来平滑我们的 CPU 使用率:
第一个是预取,它的基本思想是:预取允许 UICollectionView 告知我们的数据源,它当前不需要一个单元格,但它在不久的将来需要,因此,如果你有任何工作要做,也许现在可以提前开始 。这允许我们随时间的推移,分摊 CPU 的使用率,因此,我们减少了CPU 使用的峰值 。
另一种技术是在后台执行工作,既然我们已经随时间分散了工作量,我们也可以将这些技术分散到可用的 CPU 上 。
这样做的效果是使你的 app 具有更强的响应性,并且该设备具有更长的电池寿命 。
文章插图
具体代码如下:
func collectionView(_ collectionView: UICollectionView,prefetchItemsAt indexPaths: [IndexPath]) { // Asynchronously decode and downsample every image we are about to show for indexPath in indexPaths {DispatchQueue.global(qos: .userInitiated).async {let downsampledImage = downsample(images[indexPath.row])DispatchQueue.main.async {self.update(at: indexPath, with: downsampledImage)}} } }
我们在全局兵法队列中来使用下采样技术,但这里有个潜在的缺陷,就是有可能会引起线程爆炸 。当我们要求系统去做比 CPU 能够做的工作更多的工作时,就会发生这种情况 。【iOS性能优化之图片最佳实践】为类避免线程爆炸,我们现在不是简单的将工作分配到全局异步队列中,而是创建一个串行队列,并且在预取方法的实现中,异步的将任务分配到该队列中,实现如下:
推荐阅读
- MySQL主从延时这么长,要怎么优化?
- SUV|赛道级性能SUV来了!星途凌云S正式上市:15.99万元起
- 安装win10后,所有电脑请这样设置,性能显著提升
- NVIDIA|NVIDIA RTX 3090 Ti显存超频24GHz:挖矿性能暴涨25%
- AMD|29小时惊人续航!AMD正式发布锐龙PRO 6000:首次纳入高性能H系列
- AMD|AMD Zen5锐龙8000曝光:混合架构冲击32核、IPC性能提升将超30%
- iphone13升级ios15.1好吗??iphone12mini升级ios14.7.1?
- 微软|坐等升级!Windows 11大更新22H2曝光:9月推送、重点改进UI、性能
- SEO的精益优化方法论
- 我如何将软件系统的性能提高35,000%