Swift: 集合视图的惰性填充

Swift: lazy population of a collection view

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

    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
    }

会发生什么:

谁能解释一下这是怎么回事?

不要在回调闭包中再次调用 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
}