title: Freezes when scrolling UICollectionView
body: <p>I'm developing photo editor app, but I have a problem with render filtered images in UICollectionView. I'm using <code>Operation</code> and <code>OperationQueue</code>. When I start scrolling the collectionView, filtered images are being updated. How can I fix it?</p>
  
  <p>ImageFiltration:</p>
  
  <pre><code>class ImageFiltration: Operation {
  private let image: CIImage
  private let filterName: String!
  
  var imageWithFilter: CIImage?
  
  init(image: CIImage, filterName: String) {
      self.image = image
      self.filterName = filterName
  }
  
  override func main() {
      if self.isCancelled {
          return
      }
  
      if let name = filterName {
          let filter = CIFilter(name: name, withInputParameters: [kCIInputImageKey: image])
          imageWithFilter = filter?.outputImage!
      }
  } }
  
  class PendingOperation {
  lazy var filtrationInProgress = [IndexPath: Operation]()
  lazy var filtrationQueue: OperationQueue = {
      var queue = OperationQueue()
      queue.name = "Filtration Operation"
      return queue
  }() }
  </code></pre>
  
  <p>UIScrollViewDelegate:</p>
  
  <pre><code>extension PhotoEditorViewController: UIScrollViewDelegate {
  func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
      presenter.suspendAllOperations()
  }
  
  func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
      if !decelerate {
          presenter.loadImagesForOnScreenCells(collectionView: filtersToolsView.collectionView) { (indexPath) in
              self.filtersToolsView.collectionView.reloadItems(at: [indexPath])
          }
          presenter.resumeAllOperations()
      }
  }
  
  func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
      presenter.loadImagesForOnScreenCells(collectionView: filtersToolsView.collectionView) { (indexPath) in
          self.filtersToolsView.collectionView.reloadItems(at: [indexPath])
      }
      presenter.resumeAllOperations()
  } }
  </code></pre>
  
  <p>UICollectionView Data Source:</p>
  
  <pre><code>func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {
      let cell: PhotoEditorFilterCollectionViewCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
  
      cell.layer.shouldRasterize = true
      cell.layer.rasterizationScale = UIScreen.main.scale
      cell.filteredImage.contentMode = .scaleAspectFill
  
      presenter.startFiltration(indexPath: indexPath) { (image, filterName) in
          cell.filteredImage.inputImage = image
          cell.filterNameLabel.text = filterName
      }
  
      return cell
  }
  </code></pre>
  
  <p>Implementation start filtration method:</p>
  
  <pre><code>func startFiltration(indexPath: IndexPath, completion: @escaping (CIImage?, String) -&gt; ()) {
      if let _ = pendingOperations.filtrationInProgress[indexPath] {
          return
      }
  
      let filteredImage = ImageFiltration(image: model.image,
                                          filterName: model.image.filters[indexPath.row].filterName)
  
      filteredImage.completionBlock = {
          if filteredImage.isCancelled {
              return
          }
  
          DispatchQueue.main.async {
              self.pendingOperations.filtrationInProgress.removeValue(forKey: indexPath)
              completion(filteredImage.imageWithFilter, self.model.image.filters[indexPath.row].filterDisplayName)
          }
      }
  
      pendingOperations.filtrationInProgress[indexPath] = filteredImage
      pendingOperations.filtrationQueue.addOperation(filteredImage)
  }
  </code></pre>
  
  <p>Operation methods:</p>
  
  <pre><code>func suspendAllOperations() {
      pendingOperations.filtrationQueue.isSuspended = true
  }
  
  func resumeAllOperations() {
      pendingOperations.filtrationQueue.isSuspended = false
  }
  
  func loadImagesForOnScreenCells(collectionView: UICollectionView,
                                  completion: @escaping (IndexPath) -&gt; ()) {
      let pathsArray = collectionView.indexPathsForVisibleItems
  
      let allPendingOperations = Set(Array(pendingOperations.filtrationInProgress.keys))
      let visiblePaths = Set(pathsArray as [IndexPath])
      var toBeCancelled = allPendingOperations
  
      toBeCancelled.subtract(visiblePaths)
  
      var toBeStarted = visiblePaths
  
      toBeStarted.subtract(allPendingOperations)
  
      for indexPath in toBeCancelled {
          if let pendingFiltration = pendingOperations.filtrationInProgress[indexPath] {
              pendingFiltration.cancel()
          }
  
          pendingOperations.filtrationInProgress.removeValue(forKey: indexPath)
      }
  
      for indexPath in toBeStarted {
          let indexPath = indexPath as IndexPath
          completion(indexPath)
      }
  }
  </code></pre>
  
  <p>I'm rendering a picture in GLKView. </p>
  
  <p><a href="https://www.dropbox.com/s/u7et9wuividzehz/app.mov?dl=0" rel="nofollow noreferrer">Video</a></p>