Ios 在后台线程中加载集合视图的图像
所以我有一个集合视图,我在其中填充了141个图像,但我遇到的问题是当滚动视图时,它不是很平滑。我已经尝试过对单元格使用低分辨率图像(这有点帮助)并降低滑动速度(或者我应该说在滚动时增加减速) 所以我想我的下一步是尝试在后台线程上加载单元格 首先,我不知道怎么做,谷歌也帮不了什么忙。第二,我不确定在看不见的情况下使用单元格(所以我不创建141个单元格,每个图像一个单元格)是否会产生影响 下面是我在图像中加载的方式:Ios 在后台线程中加载集合视图的图像,ios,swift,multithreading,Ios,Swift,Multithreading,所以我有一个集合视图,我在其中填充了141个图像,但我遇到的问题是当滚动视图时,它不是很平滑。我已经尝试过对单元格使用低分辨率图像(这有点帮助)并降低滑动速度(或者我应该说在滚动时增加减速) 所以我想我的下一步是尝试在后台线程上加载单元格 首先,我不知道怎么做,谷歌也帮不了什么忙。第二,我不确定在看不见的情况下使用单元格(所以我不创建141个单元格,每个图像一个单元格)是否会产生影响 下面是我在图像中加载的方式: func collectionView(collectionView: UICol
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
s。单元格只能通过dequeueReusableCellWithReuseIdentifier
变量创建,并且UI
前缀类(UIKit
)不是线程安全的,除非明确说明。正如您所说,它将破坏单元重用,并可能导致各种内存问题
看看这个问题:
如果您不支持iOS 8,可以从后台磁盘加载映像。加载后,我会在包含图像唯一id(文件名?)的主线程上发布一个NSNotification
。所有单元格都可以侦听通知,并且–如果观察到单元格当前图像的通知–显示新的UIImage
如果您可以使用[UIImage imageNamed::
,您将免费获得一些不错的低内存反应式缓存好处。否则,您可能需要维护已加载图像的缓存(NSCache
或NSDictionary
)
如果您确实需要支持iOS 8,您仍然可以通过NSData
从后台磁盘加载图像数据,并将图像数据馈送到主线程上的UIImage
。昂贵的任务是从磁盘读取数据。如果您的图像位于资产目录中,这将需要比imageNamed
更多的工作
现在,假设您找到了一种在特定情况下在后台线程/队列上安全加载图像的方法,那么您有几个选项可以进一步优化性能:
Cap并发任务
尝试限制并发映像加载的数量,否则快速滚动会使系统充满阻塞任务和线程切换开销
可取消的任务
您应该能够取消挂起的映像加载操作。如果用户的滚动速度略快于您加载图像的速度,则您希望能够取消已移出屏幕的图像的加载。否则,您可以用看不见的图像填充队列
智能图像加载
不要加载将在毫秒内滚动掉的图像(即响应“轻弹”或快速滑动)。您可以通过连接到集合视图UIScrollViewDelegate
方法
-ScrollViewWillendDraging:withVelocity:targetContentOffset:
。通过此方法,您可以了解用户拖动内容的速度以及集合视图的最终位置。您甚至可以在目标内容偏移量附近预加载图像,以便在滚动结束时准备就绪
这类事情的一个好方法是
NSOperationQueue
,因为NSOperation
实例支持优先级排序、并发上限和并发执行。如果您使用Grand Central Dispatch,您需要建立自己“取消”任务的能力。不要尝试在后台线程上创建UICollectionViewCell
s。单元格只能通过dequeueReusableCellWithReuseIdentifier
变量创建,并且UI
前缀类(UIKit
)不是线程安全的,除非明确说明。正如您所说,它将破坏单元重用,并可能导致各种内存问题
看看这个问题:
如果您不支持iOS 8,可以从后台磁盘加载映像。加载后,我会在包含图像唯一id(文件名?)的主线程上发布一个NSNotification
。所有单元格都可以侦听通知,并且–如果观察到单元格当前图像的通知–显示新的UIImage
如果您可以使用[UIImage imageNamed::
,您将免费获得一些不错的低内存反应式缓存好处。否则,您可能需要维护已加载图像的缓存(NSCache
或NSDictionary
)
如果您确实需要支持iOS 8,您仍然可以通过NSData
从后台磁盘加载图像数据,并将图像数据馈送到主线程上的UIImage
。昂贵的任务是从磁盘读取数据。如果您的图像位于资产目录中,这将需要比imageNamed
更多的工作
现在,假设您找到了一种在特定情况下在后台线程/队列上安全加载图像的方法,那么您有几个选项可以进一步优化性能:
Cap并发任务
尝试限制并发映像加载的数量,否则快速滚动会使系统充满阻塞任务和线程切换开销
可取消的任务
您应该能够取消挂起的映像加载操作。如果用户的滚动速度略快于您加载图像的速度,则您希望能够取消已移出屏幕的图像的加载。否则,您可以用看不见的图像填充队列
智能图像加载
不要加载将在毫秒内滚动掉的图像(即响应“轻弹”或快速滑动)。您可以通过连接到集合视图UIScrollViewDeleg来解决这个问题