我正在开发照片编辑器应用程序,但在 UICollectionView 中渲染过滤图像时遇到问题。我正在使用Operation
和OperationQueue
。当我开始滚动 collectionView 时,过滤后的图像正在更新。我该如何解决?
图像过滤:
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
}() }
UIScrollViewDelegate:
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()
} }
UICollectionView 数据源:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> 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
}
实现启动过滤方法:
func startFiltration(indexPath: IndexPath, completion: @escaping (CIImage?, String) -> ()) {
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)
}
操作方法:
func suspendAllOperations() {
pendingOperations.filtrationQueue.isSuspended = true
}
func resumeAllOperations() {
pendingOperations.filtrationQueue.isSuspended = false
}
func loadImagesForOnScreenCells(collectionView: UICollectionView,
completion: @escaping (IndexPath) -> ()) {
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)
}
}
我在 GLKView 中渲染一张图片。