Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift:集合视图的惰性填充_Ios_Swift_Uiimageview_Uicollectionview_Lazy Loading - Fatal编程技术网

Ios Swift:集合视图的惰性填充

Ios Swift:集合视图的惰性填充,ios,swift,uiimageview,uicollectionview,lazy-loading,Ios,Swift,Uiimageview,Uicollectionview,Lazy Loading,我正在学习Swift,并编写一个小应用程序,用图像显示收藏视图。它不工作,而且图像永远不会显示。我在collectionView cellForItemAtIndexPath中看到了奇怪的行为:当我惰性地加载要在单元格中显示的图像并第二次调用collectionView.dequeueReusableCellWithReuseIdentifier()时,它返回一个不同的单元格。这发生在我滚动集合视图之前,所以单元重用应该不是问题。这是我的密码: func collectionView(c

我正在学习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()
    返回的单元格与方法开头返回的单元格不同。这似乎是问题的根源

有人能解释一下这里发生了什么吗?

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

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

非常感谢。这确实会导致图像显示在单元格中,但此代码也有一个问题:它通常在单元格回收后显示图像。这意味着图像显示在错误的单元格中。这就是我在回调中第二次得到单元格的原因。是的,您可以使用一个允许在重用单元格时使回调无效的抽象(例如),也可以在闭包内调用tableView.CellForRowatineXpath。你不应该让一个新的牢房排队。好的,我知道我的错误是什么。在回调中,我再次将单元格从队列中移出,而不是调用
cellForItemAtIndexPath
。我打赌就是这样。如果你想用这个建议更新你的答案,我会接受。好的,更新答案。我一直提到你必须在主线程中设置图像。干杯,谢谢。顺便说一句,据我所知,回调是在主线程上执行的,没有任何额外的代码(它是在方法调用所在的线程上执行的,对于
cellForItemAtIndexPath
,它是主线程)。谢谢。这确实会导致图像显示在单元格中,但此代码也有一个问题:它通常在单元格回收后显示图像。这意味着图像显示在错误的单元格中。这就是我在回调中第二次得到单元格的原因。是的,您可以使用一个允许在重用单元格时使回调无效的抽象(例如),也可以在闭包内调用tableView.CellForRowatineXpath。你不应该让一个新的牢房排队。好的,我知道我的错误是什么。在回调中,我再次将单元格从队列中移出,而不是调用
cellForItemAtIndexPath
。我打赌就是这样。如果你想用这个建议更新你的答案,我会接受。好的,更新答案。我一直提到你必须在主线程中设置图像。干杯,谢谢。顺便说一句,据我所知,回调是在主线程上执行的,没有任何额外的代码(它是在方法调用所在的线程上执行的,对于
cellForItemAtIndexPath
,它是主线程)。