某些上下文:我有一个UICollectionView
,它将显示大约一千个微小图像,但其中只有大约100个可同时显示。iOS:保持用户界面在图像加载到单独线程时响应
我需要在单独的线程中从磁盘加载此图像,以便UI不会被阻止,并且用户可以在图像仍然出现时与应用程序进行交互。
要做到这一点,我在斯威夫特实施rob mayoff's answer到Proper way to deal with cell reuse with background threads?如下,其中PotoCell
是UICollectionViewCell
一个子类:
var myQueue = dispatch_queue_create("com.dignityValley.Autoescuela3.photoQueue", DISPATCH_QUEUE_SERIAL)
var indexPathsNeedingImages = NSMutableSet()
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoCell
cell.imageView.image = nil
indexPathsNeedingImages.addObject(indexPath)
dispatch_async(myQueue) { self.bg_loadOneImage() }
return cell
}
func bg_loadOneImage() {
var indexPath: NSIndexPath?
dispatch_sync(dispatch_get_main_queue()) {
indexPath = self.indexPathsNeedingImages.anyObject() as? NSIndexPath
if let indexPath = indexPath {
self.indexPathsNeedingImages.removeObject(indexPath)
}
}
if let indexPath = indexPath {
bg_loadImageForRowAtIndexPath(indexPath)
}
}
func bg_loadImageForRowAtIndexPath(indexPath: NSIndexPath) {
if let cell = self.cellForItemAtIndexPath(indexPath) as? PhotoCell {
if let image = self.photoForIndexPath(indexPath) {
dispatch_async(dispatch_get_main_queue()) {
cell.imageView.image = image
self.indexPathsNeedingImages.removeObject(indexPath)
}
}
}
}
func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
indexPathsNeedingImages.removeObject(indexPath)
}
但是,我没有得到满意的结果:当我滚动时,当图像在后台加载时,UI会冻结几分之一秒。滚动不够流畅。此外,在加载前100张图像时,我无法滚动显示最后一张图像。在执行多线程之后,UI仍然被阻塞。这previosly我使用的是自定义的串行队列
var myQueue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)
注:
出人意料的是,我可以通过修改我的队列,以达到理想的平整度。
在这个改变后,用户界面完全响应,但现在我有一个非常严重的问题:我的应用程序偶尔崩溃,我认为它与几个线程可能正在访问和修改indexPathsNeedingImages
时间。
试图使用锁定/同步使我的图像有时结束到错误的单元格。所以,我想实现平滑性,它给我一个全局背景队列,但使用cutom串行队列。我无法弄清楚当我使用自定义串行队列时为什么我的UI会冻结,以及为什么当我使用全局队列时不会。
一些想法:也许设置cell.imageView.image = image
周边的100个细胞发生即使image
已经被分配一定的时间。问题可能在这里,因为评论这条线使滚动方式更顺畅。但我不明白的是,为什么滚动是平滑的,当我离开这条线时,我使用了一个全局的后台优先级队列(直到应用程序崩溃时抛出一条消息告诉... was mutated while being enumerated
)。
有关如何解决此问题的任何想法?