所以我有一个 Collection View ,我在其中填充了 141 张图像,但我遇到的问题是在 ScrollView 时,它不是很流畅。我已经尝试过为单元格使用低分辨率图像(这略有帮助)并降低滑动速度(或者我应该说在滚动时增加减速)。
所以我认为我的下一步是尝试在后台线程上加载单元格?
首先,我不知道该怎么做,谷歌也帮不上什么忙。其次,我不确定我在单元格离开视野时重新使用单元格这一事实(因此我没有创建 141 个单元格,每个图像一个单元格)是否有所不同。
这是我加载图片的方式:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TreeCell", forIndexPath: indexPath) as? TreeCell {
cell.contentView.backgroundColor = UIColor.clearColor()
let tree = Tree(treeNumber: (indexPath.row + 1))
cell.configureCell(tree)
return cell
}
else {
return UICollectionViewCell()
}
}
TreeCell 为任何人提问:
var tree: Tree!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
layer.cornerRadius = 10.0
}
func configureCell(tree: Tree) {
self.tree = tree
treeCellImage.image = UIImage(named: "\(self.tree.treeNumber)")
}
还有树类:
private var _treeNumber: Int!
init(treeNumber: Int) {
_treeNumber = treeNumber
}
var treeNumber: Int {
return _treeNumber
}
最佳答案
不要尝试在后台线程上创建 UICollectionViewCell
。单元格只能通过 dequeueReusableCellWithReuseIdentifier
变体创建,并且 UI
前缀类 (UIKit
) 不是线程安全的,除非明确说明。正如您所说,它会破坏单元重用并可能导致各种内存问题。
查看这个 SO 问题:Load UIImage in background Thread
如果您不支持 iOS 8,您可以在后台从磁盘加载图像。载入后,我会在包含图像唯一 ID(文件名?)的主线程上发布 NSNotification
。所有单元格都可以收听通知,并且 - 如果针对单元格的当前图像观察到通知 - 显示新的 UIImage
。
如果您可以使用 [UIImage imageNamed:]
,您将免费获得一些不错的低内存响应式缓存优势。否则,您可能需要维护已加载图像的缓存(NSCache
或 NSDictionary
)。
如果你确实需要支持 iOS 8,你仍然可以在后台通过 NSData
从磁盘加载图像数据,并将图像数据提供给 UIImage
主线程。昂贵的任务是从磁盘读取。如果您的图像在 Assets 目录中,这将比 imageNamed
需要更多的工作。
现在,假设您找到了一种在您的特定情况下可以在后台线程/队列上安全加载图像的方法,您有几个选项可以进一步优化性能:
限制并发任务
尝试限制并发图像加载的数量,否则快速滚动会使系统因阻塞任务和线程切换开销而饱和。
可取消任务
您应该能够取消挂起的图像加载操作。如果用户滚动的速度比您加载图像的速度快一点,您希望能够取消加载已经移出屏幕的图像。否则,您可能会用看不见的图像填满队列。
智能图片加载
不要加载将在几毫秒内滚动离开的图像(即响应“轻弹”或快速滑动)。您可以通过连接到 Collection View UIScrollViewDelegate
方法 来解决这个问题
-scrollViewWillEndDragging:withVelocity:targetContentOffset:
。此方法让您知道用户拖动内容的速度以及 Collection View 将在何处结束。您甚至可以预加载目标内容偏移量附近的图像,以便在滚动结束时准备就绪!
NSOperationQueue
对这类事情有好处,因为 NSOperation
实例支持优先级排序、并发上限和并发执行。如果您使用 Grand Central Dispatch,则需要构建自己“取消”任务的能力。
关于ios - 在后台线程中为 Collection View 加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36510209/