swift iOS – 快速滚动后混合的UICollectionView图像
我是
swift和iOS编程的新手,但我已经能够在
Xcode中为我的应用程序构建一个基本稳定的启动界面. CollectionView从我家庭网络服务器上的csv文件创建的字典数组中获取图像和文本. cvs文件包含以下格式的数据(注意,已更改URL以保护许可图像):
csv文件 csv file is @ url https://myserver.com/csv.txt and contains the following Title";"SeriesImageURL Title1";"https://licensedimage.com/url1 Title2";"https://licensedimage.com/url2 ... Title1000";"https://licensedimage.com/url1000 问题是当快速滚动CollectionView时,单元格将抓取不正确的图像.值得注意的是,如果您进行慢速或中速滚动,则在将正确的图像渲染到正确的单元格之前将显示不同的图像(单元格的标签文本始终是正确的,只有图像永远关闭).在图像与具有标签的正确单元格不匹配之后,CollectionView中的所有其他单元格也将显示不正确的图像. 例如.单元格1-9将显示具有正确Image1-9的Title1-9 我认为这个错误或者是因为没有正确处理单元重用,没有正确处理图像的缓存,或者两者兼而有之.它也可能是我作为初学者iOS / swift程序员看不到的东西.我试图用完成修饰符实现一个请求,但似乎无法使我的代码设置方式正常工作.我将不胜感激任何帮助,并解释为什么修复工作的方式.谢谢! 相关代码如下. SeriesCollectionViewController.swift class SeriesCollectionViewController: UICollectionViewController,UISearchBarDelegate { let reuseIdentifier:String = "SeriesCell" // Set Data Source Models & Variables struct seriesModel { let title: AnyObject let seriesimageurl: AnyObject } var seriesDict = [String:AnyObject]() var seriesArray = [seriesModel]() // Image Cache var imageCache = NSCache() override func viewDidLoad() { super.viewDidLoad() // Grab Data from Source do { let url = NSURL(string: "https://myserver.com/csv.txt") let fullText = try NSString(contentsOfURL: url!,encoding: NSUTF8StringEncoding) let readings = fullText.componentsSeparatedByString("n") as [String] var seriesDictCount = readings.count seriesDictCount -= 1 for i in 1..<seriesDictCount { let seriesData = readings[i].componentsSeparatedByString("";"") seriesDict["Title"] = "(seriesData[0])" seriesDict["SeriesImageURL"] = "(seriesData[1])" seriesArray.append(seriesModel( title: seriesDict["Title"]!,seriesimageurl: seriesDict["SeriesImageURL"]!,)) } } catch let error as NSError { print("Error: (error)") } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() imageCache.removeAllObjects() // Dispose of any resources that can be recreated. } //... //...skipping over some stuff that isn't relevant //... override func collectionView(collectionView: UICollectionView,cellForItemAtIndexPath indexPath: NSIndexPath) -> SeriesCollectionViewCell { let cell: SeriesCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier,forIndexPath: indexPath) as! SeriesCollectionViewCell if (self.searchBarActive) { let series = seriesArrayForSearchResult[indexPath.row] do { // set image if let imageURL = NSURL(string: "(series.seriesimageurl)") { if let image = imageCache.objectForKey(imageURL) as? UIImage { cell.seriesImage.image = image } else { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0),{ if let tvimageData = NSData(contentsOfURL: imageURL) { let image = UIImage(data: tvimageData) self.imageCache.setObject(image!,forKey: imageURL) dispatch_async(dispatch_get_main_queue(),{ () -> Void in cell.seriesImage.image = nil cell.seriesImage.image = image }) } }) } } cell.seriesLabel.text = "(series.title)" } } else { let series = seriesArray[indexPath.row] do { // set image if let imageURL = NSURL(string: "(series.seriesimageurl)") { if let image = imageCache.objectForKey(imageURL) as? UIImage { cell.seriesImage.image = image } else { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,forKey: imageURL) dispatch_async(dispatch_get_main_queue(),{ () -> Void in cell.seriesImage.image = nil cell.seriesImage.image = image }) } }) } } cell.seriesLabel.text = "(series.title)" } } cell.layer.shouldRasterize = true cell.layer.rasterizationScale = UIScreen.mainScreen().scale cell.prepareForReuse() return cell } SeriesCollectionViewCell class SeriesCollectionViewCell: UICollectionViewCell { @IBOutlet weak var seriesImage: UIImageView! @IBOutlet weak var seriesLabel: UILabel! }
您需要了解dequeue如何正常工作.有很好的文章.
总结一下:
现在,当你这样做时 – let cell: SeriesCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier,forIndexPath: indexPath) as! SeriesCollectionViewCell 您正在重用已经制作的单元格中的现有单元格.这就是为什么你会看到旧图像一段时间然后在加载后看到新图像的原因. 您需要在单元格出列后立即清除旧图像. cell.seriesImage.image = UIImage() //nil 实际上,您将在图像中以这种方式设置一个空白占位符,而不是在您的情况下将imageCache设置为nil. 这解决了这个问题 –
现在,在为当前单元格分配图像时,如果要分配的图像属于此单元格,则需要再次检查.您需要检查这一点,因为您正在重新分配它的图像视图,它可能与indexPath上的单元格关联,而不是生成图像加载请求时的单元格. 当您将单元格出列并将image属性设置为nil时,请让seriesImage为您记住当前的indexPath. cell.seriesImage.indexPath = indexPath 稍后,如果imageView仍属于先前分配的indexPath,则仅将图像分配给它.这与细胞重用100%有效. if cell.seriesImage.indexPath == indexPath cell.seriesImage.image = image 您可能需要考虑在UIImageView实例上设置indexPath.这是我准备并用于类似场景的东西 – 它既有Objective-C又有.迅速. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- I/O 设计模式 Reactor 和 Proactor
- 【swift】15-0526 标签,函数
- c# – 绑定FontFamily ViewModel的属性
- postgresql – SQLAlchemy支持Postgres Schemas
- 数组 – 使用SimpleXMLElement和keys数组的Twig“in”运算符
- c# – 何时返回IEnumerable
- ruby-on-rails – 无法在CommentsController中重定向到Nil
- SQLite查询插入记录如果不存在
- NoSQL数据库探讨之一 - 为什么要用非关系数据库?
- [System Design] 系统设计 (3) -- OOD