Search code examples
swift3uicollectionviewreloaddata

Collection view doesn't reload (Swift)


I'm building an app (in swift). One of the options should be to allow the user to either select multiple photos and upload them or take a photo and create a post with it. My idea is based the following hierarchy:

New Photo post button pressed -> User is presented with UICollection view controller with all photos from their library and an option to select multiple photos (I'm reusing a cell to populate those collection view with the images from the photo library) and above that should be the Camera cell (the user needs to click on the button to allow access to the camera in order to take a photo). Here's a representation from the Simulator.

enter image description here

I've written the code that gets the photos from library and add them in an array here (I'll show the code for these below). The problem is when you initially load the app for the first time and try to post, you're being asked to grant access to the photos. Despite of the user's choice, (either they agree or don't) they collection view isn't update.

What it needs to happen - When the user is asked to grant access to Photos and they click "OK", it should reload the data in the collection view, but it doesn't. And when they click on "Don't allow" it should dismiss the entire View controller. Here's my code

class CVController: UICollectionViewController, UINavigationControllerDelegate, UICollectionViewDelegateFlowLayout {

var photosLibraryArray = [UIImage]()

override func viewDidLoad() {
    super.viewDidLoad()

    grabAllPhotosFromPhoneLibrary()

}

// Grab All Photos from Library
func grabAllPhotosFromPhoneLibrary () {

    let imageManager = PHImageManager.default()

    let requestOptions = PHImageRequestOptions()
    requestOptions.isSynchronous = true  // synchronous works better when grabbing all images
    requestOptions.deliveryMode = .opportunistic

    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)] // if false = last image we took would show first

    let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)

    // 1. Are there photos in the library
    if fetchResult.count > 0 {

        // 2. if fetch.count > 0 it means there's at least 1 photo in the library
        for i in 0..<fetchResult.count {

            // 3. Cycling through the photos
            imageManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler:

                { image, error in
                    // 4. Append each image in the array
                    self.photosLibraryArray.append(image!)
            })
        }

    } else {
        print("You've got no photos")
        self.collectionView?.reloadData()
    }

I tried calling collectionView.reloadData() in the viewWillApear(), viewDidApear(), nothing worked.


Solution

  •     class CVController: UICollectionViewController, UINavigationControllerDelegate, UICollectionViewDelegateFlowLayout {
    
        var photosLibraryArray = [UIImage]()
    
        override func viewDidLoad() {
        super.viewDidLoad()
    
            checkPhotoLibraryPermission()
        }
    

    Add this below mentioned function

        func checkPhotoLibraryPermission() {
            let status = PHPhotoLibrary.authorizationStatus()
            switch status {
            case .authorized: 
            //handle authorized status - // call this function here
                    grabAllPhotosFromPhoneLibrary()
                case .denied, .restricted : 
                    //handle denied status
                case .notDetermined: 
                    // ask for permissions
                    PHPhotoLibrary.requestAuthorization() { status in
                        switch status {
                        case .authorized: 
                            // call this function here
                            grabAllPhotosFromPhoneLibrary()
    
                        case .denied, .restricted: 
                            // as above
                            _ = navigationController?.popViewController(animated: true)
                        case .notDetermined: 
                            // won't happen but still, if you want to handle.
                    }
            }
        }
        }
    

    You may accordingly make changes in the following function below. As per the need.

        // Grab All Photos from Library
        func grabAllPhotosFromPhoneLibrary () {
    
        let imageManager = PHImageManager.default()
    
        let requestOptions = PHImageRequestOptions()
        requestOptions.isSynchronous = true  // synchronous works better when grabbing all images
        requestOptions.deliveryMode = .opportunistic
    
        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)] // if false = last image we took would show first
    
        let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
    
        // 1. Are there photos in the library
        if fetchResult.count > 0 {
    
            // 2. if fetch.count > 0 it means there's at least 1 photo in the library
            for i in 0..<fetchResult.count {
    
                // 3. Cycling through the photos
                imageManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler:
    
                    { image, error in
                        // 4. Append each image in the array
                        self.photosLibraryArray.append(image!)
                })
            }
        //Use this reload data here as - you want the data loaded in the array first and then show the data.
    
        self.collectionView?.reloadData()
    
        } else {
            print("You've got no photos")
            //self.collectionView?.reloadData()
    
            // if you want to hide the view controller when there is no photo. pop the view controller from your navigation controller like this. 
    
         _ = navigationController?.popViewController(animated: true)
        }