Part_Time_Nerd
Part_Time_Nerd

Reputation: 1014

UICollectionView is coming up blank

I am trying to fill a UICollectionView with images from the PhotoLibrary but when I run the code the screen comes up blank. I am new to Swift so I am assuming my issue is something simple but I cannot figure out what I am doing wrong or why it shows up blank. What am I doing wrong?

import UIKit
import Photos

private let reuseIdentifier = "Cell"

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
        
    var imageArray = [UIImage]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
        grabPhotos()
    }
    
    func grabPhotos(){
    
        let imgManager = PHImageManager.default()
        let requestOptions = PHImageRequestOptions()
        requestOptions.isSynchronous = true
        requestOptions.deliveryMode = .highQualityFormat
        
        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: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
                        image, error in
                        self.imageArray.append(image!)
                    })
                }
            } else {
                print("you do not have any photos")
                self.collectionView?.reloadData()
            }
        }
    }

    // MARK: UICollectionViewDataSource
    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return imageArray.count
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 0
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
        let imageView = cell.viewWithTag(1) as! UIImageView
        imageView.image = imageArray[indexPath.row]
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = collectionView.frame.width / 3 - 1
        return CGSize(width: width, height: width)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 1.0
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 1.0
    }
}

Upvotes: 0

Views: 57

Answers (1)

DonMag
DonMag

Reputation: 77691

In this block of code:

    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: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
                    image, error in
                    self.imageArray.append(image!)
                })
            }
        } else {
            print("you do not have any photos")
            self.collectionView?.reloadData()
        }
    }

You are saying:

"If count is greater than zero, append the images to the array. Else, reload the collection view data."

Add the reload line after you've updated your data array:

    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: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
                    image, error in
                    self.imageArray.append(image!)
                })
            }
            // make sure this is called on the main thread
            DispatchQueue.main.async {
                self.collectionView?.reloadData()
            }
        } else {
            print("you do not have any photos")
            self.collectionView?.reloadData()
        }
    }

Edit in response to your comment...

After reviewing your code a bit, you are doing many, many things wrong.

To start with, you are registering a default UICollectionViewCell, then trying to access a UIImageView in that cell with cell.viewWithTag(1) as! UIImageView --- which will never succeed.

Next, you are trying to return the number of photos loaded as the numberOfSections in the collection view, and then returning 0 (zero) as the numberOfItemsInSection for each section. So, even if you successfully load images, nothing will ever be displayed.

Third, loading the assets and getting images are asynchronous processes. You're not doing that correctly at all.

I strongly suggest that you first go through some tutorials on collection views and custom cells. Learn how that works first.

Then, go through some tutorials on loading images from the device.

Then, work on putting it all together.

Apple has a sample app that demonstrates displaying assets in a thumbnail grid, that covers all of these tasks. It's out-of-date (Swift 3) so you would need to do some manual fixes to the code... but, in the process of making those fixes, you would likely learn a bit anyway.

Upvotes: 2

Related Questions