I am loading the photos from a users photo album into a collection view similar to how is done in this Apple Sample project. I can not seem to track down why the memory is growing out of control. I use the suggested PHCachingImageManager but all that results are blurry images, freezing scrolling and memory growing out of control until the application crashes.
In my viewDidLoad I run the code below
PHPhotoLibrary.requestAuthorization { (status: PHAuthorizationStatus) in
print("photo authorization status: \(status)")
if status == .authorized && self.fetchResult == nil {
print("authorized")
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
var tempArr:[PHAsset] = []
self.fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
guard let fetchResult = self.fetchResult else{
print("Fetch result is empty")
return
}
fetchResult.enumerateObjects({asset, index, stop in
tempArr.append(asset)
})
// self.assets = tempArr
self.imageManager.startCachingImages(for: tempArr, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: nil)
tempArr.removeAll()
print("Asset count after initial fetch: \(self.assets?.count)")
DispatchQueue.main.async {
// Reload collection view once we've determined our Photos permissions.
print("inside of main queue reload")
PHPhotoLibrary.shared().register(self)
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.reloadData()
}
} else {
print("photo access denied")
self.displayPhotoAccessDeniedAlert()
}
}
and inside of cellForItemAt: I run the following code
cellForItemAt
guard let fetchResult = self.fetchResult else{
print("Fetch Result is empty")
return UICollectionViewCell()
}
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = false
requestOptions.deliveryMode = .highQualityFormat
//let scale = min(2.0, UIScreen.main.scale)
let scale = UIScreen.main.scale
let targetSize = CGSize(width: cell.bounds.width * scale, height: cell.bounds.height * scale)
// let asset = assets[indexPath.item]
let asset = fetchResult.object(at: indexPath.item)
let assetIdentifier = asset.localIdentifier
cell.representedAssetIdentifier = assetIdentifier
imageManager.requestImage(for: asset, targetSize: cell.frame.size,
contentMode: .aspectFill, options: requestOptions) { (image, hashable) in
if let loadedImage = image, let cellIdentifier = cell.representedAssetIdentifier {
// Verify that the cell still has the same asset identifier,
// so the image in a reused cell is not overwritten.
if cellIdentifier == assetIdentifier {
cell.imageView.image = loadedImage
}
}
}
I had a similar problem this week using the Apple Code which for others reference is available here Browsing & Modifying Photos
Memory usage was very high, and then if viewing a single item and returning to root, memory would spike and the example would crash.
As such from our experiments there were a few tweaks which improved performance.
Firstly when setting the thumbnailSize for the requestImage function:
We set the scale like so instead of using the full size:
We also set the
PHImageRequestOptions Resizing Modeto.fast.As well as this we found that setting the following variables of the
CollectionViewCellalso helped somewhat:We also noticed that the
updateCachedAssets()in theScrollViewwDidScrollmethod was playing some part in this process so we removed that from this callback(rightly or wrongly).And one final thing was the we kept a reference to the
PHCachingImageManagerfor each cell and if it existed then we called:As such here is the code for our
MediaCell:And the code for the
cellForItem:One additional area is in the updateCachedAssets() funtion. You are using:
It would probably be best to set a smaller size here e.g:
Whereby thumbnail size e.g:
All of these tweaks helped to ensure that the memory usage remained fair constant, and in our testing ensured that there were no exceptions thrown.
Hope it helps.