为什么collectionView会在滚动时冻结?

时间:2016-03-06 11:23:48

标签: ios swift asynchronous uicollectionview

我正在尝试使用照片过滤器创建一个简单的应用,例如Instagram。所以,我捕获我的图像然后我需要对此图像实现过滤器。在底部我有一个UICollectionView(水平滚动),在那里我可以看到我有什么过滤器以及它们在我的图像上的外观。

但是当我滚动我的UICollectionView时 - 它冻结并且我的过滤器应用于每个新单元格(因为重用过程)。但是Instagram如何做到这一点当我滚动过滤器时它们不会冻结?

我试过这个:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: imageFilterCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! imageFilterCell

let queue = NSOperationQueue()

    let op1 = NSBlockOperation { () -> Void in
        let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
        let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])

        NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
            cell.imageView.image = img1
        })
    }

    queue.addOperation(op1);

    return cell
}

但它仍然在滚动时冻结,我看到每次我的过滤器应用于我的单元格时。我可以只做一次然后滚动无所事事,只显示实施过滤器后照片的外观吗?

3 个答案:

答案 0 :(得分:2)

你可以做以下两件事之一:

  1. 请勿使用集合视图的重用功能。简单地创造 一系列单元格并将这些单元格传递给cellForRowAtIndexPath。如果你这应该工作正常 没有大量的过滤器。类似的东西:

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        var cell: imageFilterCell? = nil
        if (cellsArray.count <= indexPath.row) {
            //This assumes imageFilterCell is created in code
            //If you use storyboards or xibs load it accordingly
            cell = imageFilterCell()
            cellsArray.append(cell)
        } else {
            cell = cellsArray[indexPath.row]
        }
        let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
        dispatch_async(dispatch_get_global_queue(priority, 0)) {
           let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
           let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])
    
           dispatch_async(dispatch_get_main_queue()) {
                 cell!.imageView.image = img1
           }
    }
    
        return cell
    

    }

  2. 为异步操作实现取消机制,因为如果在后台线程仍在应用过滤器的情况下重用该单元,则最终单元将最终具有多个过滤器。为此,您可以使用cancel类中的NSOperation方法。为此,您可以在自定义单元格上创建名为operation的属性,例如:

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell: imageFilterCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! imageFilterCell
        cell.operation.cancel()    
    
        //make the queue an instance variable
        //let queue = NSOperationQueue()
    
        let op1 = NSBlockOperation { () -> Void in
            let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
            let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])
    
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                cell.imageView.image = img1
            })
        }
    
        queue.addOperation(op1);
        cell.operation = op1
    
        return cell
    

    }

答案 1 :(得分:0)

你正在主线程中处理,这就是冻结的原因。

使用Concurrent Dispatch Queue获得更流畅的体验。

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

    let cell: imageFilterCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! imageFilterCell


   let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
   dispatch_async(dispatch_get_global_queue(priority, 0)) {
           let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
           let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])

           dispatch_async(dispatch_get_main_queue()) {
                 cell.imageView.image = img1
           }
    }

        return cell
}

答案 2 :(得分:0)

您可以在内存中缓存数据(图像) 它的问题与读取数据(图像)有很好的关系:D