我正在开发照片编辑器应用程序,但我在UICollectionView中渲染过滤图像时遇到问题。我正在使用Operation
和OperationQueue
。当我开始滚动collectionView时,正在更新过滤的图像。我该如何解决?
ImageFiltration:
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中渲染图片。
答案 0 :(得分:1)
在scrollViewDidScroll上取消所有请求。最后滚动获取可见单元格并启动操作队列。这样它只会使用你的可见单元格内存,UI也不会卡住。 请参阅本教程,与您的要求相同 - https://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift