swift iOS – 快速滚动后混合的UICollectionView图像

前端之家收集整理的这篇文章主要介绍了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
当缓慢滚动时,单元格19-27将显示标题19-27,将简要显示图像10-18,然后显示正确的图像19-27.
快速滚动大量单元格时(例如从单元格1-9到单元格90-99),单元格90-99将显示标题90-99,将显示图像10-50ish,然后将错误地保留在图像41-50 (或左右).当进一步滚动时,单元格100将显示正确的标题,但仅显示图像41-50范围内的图像.

我认为这个错误或者是因为没有正确处理单元重用,没有正确处理图像的缓存,或者两者兼而有之.它也可能是我作为初学者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如何正常工作.有很好的文章.

总结一下:

To maintain scrolling smoothness,dequeue is used which essentially
reuses cells after a certain limit. Say you have 10 visible cells at a
time,it will likely create 16-18 (3-4 above,3-4 below,just rough
estimates) cells only,even though you might need 1000 cells.

现在,当你这样做时 –

let cell: SeriesCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier,forIndexPath: indexPath) as! SeriesCollectionViewCell

您正在重用已经制作的单元格中的现有单元格.这就是为什么你会看到旧图像一段时间然后在加载后看到新图像的原因.

您需要在单元格出列后立即清除旧图像.

cell.seriesImage.image = UIImage()    //nil

实际上,您将在图像中以这种方式设置一个空白占位符,而不是在您的情况下将imageCache设置为nil.

解决了这个问题 –

Noticeably,if you do a slow or medium scroll,a different image will show before the correct image is rendered into the correct cell (the label text for the cells are always correct,only the image is ever off).

现在,在为当前单元格分配图像时,如果要分配的图像属于此单元格,则需要再次检查.您需要检查这一点,因为您正在重新分配它的图像视图,它可能与indexPath上的单元格关联,而不是生成图像加载请求时的单元格.

当您将单元格出列并将image属性设置为nil时,请让seriesImage为您记住当前的indexPath.

cell.seriesImage.indexPath = indexPath

稍后,如果imageView仍属于先前分配的indexPath,则仅将图像分配给它.这与细胞重用100%有效.

if cell.seriesImage.indexPath == indexPath
cell.seriesImage.image = image

您可能需要考虑在UIImageView实例上设置indexPath.这是我准备并用于类似场景的东西 –
UIView-Additions

它既有Objective-C又有.迅速.

原文链接:https://www.f2er.com/swift/319147.html

猜你在找的Swift相关文章