From 974c3fcdc43b14cc43cf8bc2d4b8562a1b8d84ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Gyllstr=C3=B6m?= Date: Fri, 17 Jul 2020 15:27:55 +0200 Subject: [PATCH] Performance optimizations - Had forgot to set prefetch data source on collection view. - Removed image size calculation on every cell dequeue. - Use PHCachingImageManager caching API. - Clear image cache when changing image size or fetch result. --- .../AssetsCollectionViewDataSource.swift | 41 +++++++++---------- .../Scene/Assets/AssetsViewController.swift | 3 ++ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Sources/Scene/Assets/AssetsCollectionViewDataSource.swift b/Sources/Scene/Assets/AssetsCollectionViewDataSource.swift index 31a28810..6ffbee38 100755 --- a/Sources/Scene/Assets/AssetsCollectionViewDataSource.swift +++ b/Sources/Scene/Assets/AssetsCollectionViewDataSource.swift @@ -28,19 +28,25 @@ class AssetsCollectionViewDataSource : NSObject, UICollectionViewDataSource { private static let videoCellIdentifier = "VideoCell" var settings: Settings! - var fetchResult: PHFetchResult + var fetchResult: PHFetchResult { + didSet { + imageManager.stopCachingImagesForAllAssets() + } + } + var imageSize: CGSize = .zero { + didSet { + imageManager.stopCachingImagesForAllAssets() + } + } - private let imageManager = PHCachingImageManager.default() + private let imageManager = PHCachingImageManager() private let durationFormatter = DateComponentsFormatter() private let store: AssetStore - - private let scale: CGFloat - private var targetSize: CGSize = .zero + private let contentMode: PHImageContentMode = .aspectFill - init(fetchResult: PHFetchResult, store: AssetStore, scale: CGFloat = UIScreen.main.scale) { + init(fetchResult: PHFetchResult, store: AssetStore) { self.fetchResult = fetchResult self.store = store - self.scale = scale durationFormatter.unitsStyle = .positional durationFormatter.zeroFormattingBehavior = [.pad] durationFormatter.allowedUnits = [.minute, .second] @@ -87,35 +93,26 @@ class AssetsCollectionViewDataSource : NSObject, UICollectionViewDataSource { collectionView?.register(VideoCollectionViewCell.self, forCellWithReuseIdentifier: videoCellIdentifier) } - private func loadImage(for asset: PHAsset, in cell: AssetCollectionViewCell?) { + private func loadImage(for asset: PHAsset, in cell: AssetCollectionViewCell) { // Cancel any pending image requests - if let cell = cell, cell.tag != 0 { + if cell.tag != 0 { imageManager.cancelImageRequest(PHImageRequestID(cell.tag)) } // Request image - if let cell = cell { - targetSize = cell.bounds.size.resize(by: scale) - } - - cell?.tag = Int(imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: settings.fetch.preview.photoOptions) { (image, _) in + cell.tag = Int(imageManager.requestImage(for: asset, targetSize: imageSize, contentMode: contentMode, options: nil) { (image, _) in guard let image = image else { return } - cell?.imageView.image = image + cell.imageView.image = image }) } } extension AssetsCollectionViewDataSource: UICollectionViewDataSourcePrefetching { func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { - // Touching asset should trigger prefetching - // And prefetch image for that asset - indexPaths.forEach { - let asset = fetchResult[$0.row] - loadImage(for: asset, in: nil) - } + let assets = indexPaths.map { fetchResult[$0.row] } + imageManager.startCachingImages(for: assets, targetSize: imageSize, contentMode: contentMode, options: nil) } func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) { - } } diff --git a/Sources/Scene/Assets/AssetsViewController.swift b/Sources/Scene/Assets/AssetsViewController.swift index e9756da2..c1c1cbc3 100644 --- a/Sources/Scene/Assets/AssetsViewController.swift +++ b/Sources/Scene/Assets/AssetsViewController.swift @@ -76,6 +76,7 @@ class AssetsViewController: UIViewController { collectionView.backgroundColor = settings.theme.backgroundColor collectionView.delegate = self collectionView.dataSource = dataSource + collectionView.prefetchDataSource = dataSource AssetsCollectionViewDataSource.registerCellIdentifiersForCollectionView(collectionView) let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(AssetsViewController.collectionViewLongPressed(_:))) @@ -158,6 +159,8 @@ class AssetsViewController: UIViewController { collectionViewFlowLayout.minimumLineSpacing = itemSpacing collectionViewFlowLayout.minimumInteritemSpacing = itemSpacing collectionViewFlowLayout.itemSize = itemSize + + dataSource.imageSize = itemSize.resize(by: UIScreen.main.scale) } private func updateSelectionIndexForCell(at indexPath: IndexPath) {