【问题标题】:Swift: lazy population of a collection viewSwift:集合视图的惰性填充
【发布时间】:2015-02-28 19:46:17
【问题描述】:

我正在学习 Swift,并且正在编写一个小应用程序来显示带有图像的集合视图。它不起作用,并且图像永远不会显示。我在collectionView cellForItemAtIndexPath 中看到了奇怪的行为:当我延迟加载要在单元格中显示的图像并第二次调用collectionView.dequeueReusableCellWithReuseIdentifier() 时,它返回一个不同的单元格。这发生在我滚动集合视图之前,因此单元格重用应该不是问题。这是我的代码:

    func collectionView(collectionView: UICollectionView,
        cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let reuseIdentifier = "CollectionCell"
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath:indexPath) as! ImageCollectionCell

        cell.imageView.contentMode = UIViewContentMode.ScaleAspectFill

        cell.countLabel.text = "\(indexPath.row+1)"

        let imageIndex = XKCDClient.sharedInstance.totalCount - indexPath.row - 1
        println("loading image # \(imageIndex)")
        XKCDClient.sharedInstance.loadComic(imageIndex, completion: { (comicData) -> Void in

            if let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath:indexPath) as? ImageCollectionCell {
                println("got image # \(imageIndex)")
                cell.imageView.backgroundColor = UIColor.blackColor()
                if(comicData.image != nil) {
//                    cell.imageView.image = comicData.image // (1)

                    cell.imageView.image = UIImage(named: "placeholder") // (2)
                    cell.setNeedsDisplay()
                }
            }
            else {
                println("cell \(imageIndex) already reused");
            }
        })

        return cell
    }

会发生什么:

  • 为每个索引路径调用回调块
  • UIImage 对象已正确传递到回调块中
  • 对回调中的单元格没有任何更改似乎有任何效果(包括设置背景颜色)
  • 回调中collectionView.dequeueReusableCellWithReuseIdentifier()返回的单元格与方法开头返回的单元格不同。这似乎是问题的根源。

谁能解释一下这里发生了什么?

【问题讨论】:

    标签: ios swift uiimageview uicollectionview lazy-loading


    【解决方案1】:

    不要在回调闭包中再次调用dequeuReusableCellWithReuseIdentifier,而是调用cellForItemAtIndexPath。注意:在单元格中设置图片时,必须在主线程中进行:

       func collectionView(collectionView: UICollectionView,
         cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    
        let reuseIdentifier = "CollectionCell"
        let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ImageCollectionCell
        cell.imageView.image = nil
        cell.imageView.contentMode = UIViewContentMode.ScaleAspectFill
        cell.countLabel.text = "\(indexPath.row+1)"
        let imageIndex = XKCDClient.sharedInstance.totalCount - indexPath.row - 1
        XKCDClient.sharedInstance.loadComic(imageIndex, completion: { (comicData) -> Void in
             if let img = comicData.image {
                 // Note: Set image in the main thread
                 dispatch_async(dispatch_get_main_queue()) {
                      cell.imageView.image = img
                 }
             } else {
                println("No image in comicData")
                dispatch_async(dispatch_get_main_queue()) {
                      cell.imageView.image = nil
                 }
             }
        })
    
        return cell
    }
    

    【讨论】:

    • 谢谢。这确实会导致单元格中显示图像,但是这段代码也有一个问题:它经常在单元格被回收后显示图像。这意味着图像显示在错误的单元格中。这实际上是我在回调中第二次获取单元格的原因。
    • 是的,您可以使用抽象允许在重用单元格时使回调无效(例如BrightFutures),或者您可以在闭包内调用 tableView.cellForRowAtIndexPath。您不应将新单元格出列。
    • 好的,我知道我的错误是什么。在回调中,我再次将单元格出列,而不是调用cellForItemAtIndexPath。我打赌就是这样。如果你想用这个建议更新你的答案,我会接受。
    • 好的,更新了答案。我一直提到你必须在主线程中设置图像。干杯。
    • 谢谢。顺便说一句,据我了解,回调是在主线程上执行的,没有任何额外的代码(它是在进行方法调用的线程上执行的,对于cellForItemAtIndexPath,它是主线程)。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    相关资源
    最近更新 更多