简体   繁体   中英

How to display photo library in collectionView using less memory

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?

PS 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()
        }
    }

}

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:

https://developer.apple.com/library/archive/samplecode/UsingPhotosFramework/Listings/Shared_AssetGridViewController_swift.html

There is no array of images anywhere in that example.

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM