Reputation: 486
I'm facing the problem that people are saying that the application crashes when loading photos library in collectionView. Most of the time they have more than 2-3 thousands of photos. For me it's working fine. (I have less than 1000 photos in my library).
Question: maybe there's any way to display images in collectionView more "smart" and using less memory?
P.S Maybe when user have all of his photos in iCloud that can cause crash too? Because until now I thought that application is not downloading photos when loading it into the cell. Maybe someone can prove or disapprove that fact.
Here's my function:
func grabPhotos(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = false
requestOptions.deliveryMode = .opportunistic // Quality of images
requestOptions.isNetworkAccessAllowed = true
requestOptions.isSynchronous = true
requestOptions.progressHandler = { (progress, error, stop, info) in
print("progress: \(progress)")
}
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i) , targetSize: CGSize(width: 150, height: 150), contentMode: .aspectFill, options: requestOptions, resultHandler: { image, error in
self.imageArray.append(image!)
self.kolekcija.reloadData()
})
}
}
else {
print("You got no photos")
kolekcija.reloadData()
}
}
}
Upvotes: 1
Views: 1515
Reputation: 367
Working in Swift 5. Get the photo assets, but don't load the photos until cellForItem iteration. Happy coding.
var personalImages: PHFetchResult<AnyObject>!
func getPersonalPhotos() {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
self.personalImages = (PHAsset.fetchAssets(with: .image, options: fetchOptions) as AnyObject?) as! PHFetchResult<AnyObject>?
photoLibraryCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return personalImages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "insertCellIdentifierHere", for: indexPath) as! InsertACollectionViewCellHere
let asset: PHAsset = self.personalImages[indexPath.item] as! PHAsset
let itemWidth = photoLibraryCollectionView.frame.size.width / 2
let itemSize = CGSize(width: itemWidth, height: itemWidth / 2) // adjust to your preferences
PHImageManager.default().requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: nil, resultHandler: {(result, info)in
if result != nil {
cell.photoImageView.image = result
}
})
cell.layoutIfNeeded()
cell.updateConstraintsIfNeeded()
return cell
}
Upvotes: 0
Reputation: 535139
The problem is this line:
self.imageArray.append(image!)
Never make an array of images. Images are huge, and you'll run out of memory.
This is a collection view. You simply supply the image on demand in itemForRowAt:
, and what you supply is a small version of the image (a so-called thumbnail), the smallest possible for the display size. Thus there are, at any time, only enough thumbnails to fill the visible screen; that doesn't take very much memory, plus the runtime can release the image memory when an image is scrolled off the screen.
That is what PHCachingImageManager is for. Look closely at how Apple handles this in their sample code:
There is no array of images anywhere in that example.
Upvotes: 3