Populating UICollectionView with Images from Camera Roll

Viewed 54

I'm trying to create a UICollectionViewController like the one in the "Photos" app on iPhone.

This is the code I'm using:

import UIKit
import Photos

private let reuseIdentifier = "dataCell"

class GalleryCollectionViewController: UICollectionViewController {

var images = [PHAsset]()

override func viewDidLoad() {
    super.viewDidLoad()
    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Register cell classes
    self.collectionView!.register(GalleryImageCell.self, forCellWithReuseIdentifier: reuseIdentifier)
    getImages()
    // Do any additional setup after loading the view.
}

func getImages() {
    let assets = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil)
    assets.enumerateObjects({ (object, count, stop) in
       // self.cameraAssets.add(object)
        self.images.append(object)
    })

    self.images.reverse()

    self.collectionView!.reloadData()
}

/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

// MARK: UICollectionViewDataSource

override func numberOfSections(in collectionView: UICollectionView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}


override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of items
    return images.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "dataCell", for: indexPath) as! GalleryImageCell
    
    let asset = images[indexPath.row]
    let ImageManager = PHImageManager.default()
    if cell.tag != 0 {
        ImageManager.cancelImageRequest(PHImageRequestID(cell.tag))
    }
    
    cell.tag = Int(ImageManager.requestImage(for: asset, targetSize: CGSize(width: 120, height: 120), contentMode: .aspectFill, options: nil, resultHandler: { (result, _) in
        cell.galleryImage?.image = result
    }))
    
    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = self.view.frame.width * 0.32
    let height = self.view.frame.height * 0.179910045
    return CGSize(width: width, height: height)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 2.5
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}

}

Anyway, when I load the view I only get a black view. The images are not displayed at all even though the cells seem to be created as the view scrolls for a good amount of time. It is not a problem related to Privacy Permissions as I've already granted access to "All Photos" and because images contains all the photos assets.

Do you know what I might be doing wrong? Thank you in advance

1 Answers

Are you certain that your images are being appended inside the block?

I'm loading PHAssets in my app by doing the following anyway, see if it helps you out:

I initially do this:

let assetFetcher = PHAssetFetcher(configuration: configuration)
    assetFetcher.fetchAssets { [weak self] (fetchResult) in
        guard let `self` = self, let fetchResult = fetchResult else { return }
        self.fetchResult = fetchResult
        let assets = fetchResult.objects(at: IndexSet(integersIn: 0..<fetchResult.count))
    }

So this loads the assets from the gallery, but then you might have to do some work depending on what the Asset is (video, photo, burst, gif, etc...) You can check the typeIdentifier of the asset to see which asset is in what category, and then retrieve the relevant image there. For example if the image is just a photo then you'll just use the image associated, but if it's a video then you might want to show only a thumbnail, that comes back to you. Either way, working with the Photos API can be a tad tedious, but it's a big learning experience.

Related