Repaz Kung
Repaz Kung

Reputation: 43

Photos not showing in collection view

When I open my application it asks me for permission to access my photos. That is all all right. But after accepting, the screen turns black and shows no photos and in my console it says that it has found no photos. Although I have photos on my device.

import UIKit
import Photos

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
    var imageArray = [UIImage]()

    override func viewDidLoad() {
        grabPhotos()
    }

    func grabPhotos(){
        let imgManager = PHImageManager.defaultManager()

        let requestOptions = PHImageRequestOptions()
        requestOptions.synchronous = true
        requestOptions.deliveryMode = .HighQualityFormat

        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key:"CreationDate" , ascending: false)]

        if let fetchResult : PHFetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: fetchOptions){
            if fetchResult.count > 0 {
                for i in 0..<fetchResult.count{
                    imgManager.requestImageForAsset(fetchResult.objectAtIndex(i) as! PHAsset, targetSize: CGSize(width: 200, height: 200), contentMode: .AspectFill, options: requestOptions, resultHandler: {

                        image, error in

                        self.imageArray.append(image!)
                    })
                }
            }
            else{
                print("You have got not photos!")
                self.collectionView?.reloadData()
            }
        }
    }

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imageArray.count
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)

        let imageView = cell.viewWithTag(1) as! UIImageView

        imageView.image = imageArray[indexPath.row]

        return cell
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        let width = collectionView.frame.width / 3 - 1

        return CGSize(width: width, height: width)
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
        return 1.0
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
        return 1.0
    }
}

Upvotes: 0

Views: 1265

Answers (3)

rickster
rickster

Reputation: 126127

Most likely the problem here is that you're asking for assets only once. The first time you ask, you get nothing. When you call PHAsset.fetchAssetsWithMediaType, it does two things at the same time: It asks the user for authorization, and because authorization hasn't been granted yet (the authorization prompt is still on screen), it returns an empty fetch result. (And because the fetch result is empty, you can't

If that's the problem, you should see a non-empty fetch result the second time you run your app (because authorization is a one-time thing and persists across launches).

There are a few ways to deal with this...

  • One is simply to request authorization directly first using requestAuthorization() and fetch assets only after that call's completion handler fires (with a positive result).

  • Another is to register() your view controller (or some other controller class of yours) as an observer of the Photos library before performing a fetch. Your first fetch before authorization still returns an empty result, but as soon as the user has authorized your app your observer gets a photoLibraryDidChange() call from which you can access the full, "real" fetch results.


Beyond that, there are some other things you're doing that aren't best practice here...

  • You're requesting images from the PHImageManager for every asset in the library, regardless of whether the user is going to see them. Consider the case of someone whose iCloud Photo Library contains tens of thousands of assets — only the first 30 or so are going to fit on your collection view at once, and the user may never scroll all the way to the end, but you're still fetching thumbnails for Every Image Ever. (And in the case of iCloud assets not on the local device, trigging network activity for lots of thumbnails the user might never see.)

  • You're getting thumbnails from PHImageManager synchronously and sequentially. Once you get the authorization issue dealt with, your app will probably crash because your for i in 0..<fetchResult.count { imgManager.requestImageForAsset loop blocks the main thread for too long.

Apple provides canonical example code that demonstrates how to use the Photos app to do things like displaying a collection view full of thumbnails. Take a look at AssetGridViewController.swift in that project to see some of the things they're doing:

  • use PHCachingImageManager to prefetch batches of thumbnails based on the visible area of a collection view
  • use PHPhotoLibraryObserver to react to changes in a fetch result, including animated collection view updates
  • handling the interaction between asynchronous fetches and the collection view data source
  • inserting new assets in the Photos library

Upvotes: 3

pedrouan
pedrouan

Reputation: 12910

1) Subclass a UICollectionViewCell:

import ...
//put this e.g. to the top of your swift file, right after import statements

class PhotoViewCell: UICollectionViewCell {

    @IBOutlet weak var myImageView: UIImageView! 

}

2) Create a prototype for you cell:

2.1 design it (you may have done before)

2.2 enter an identifier

enter image description here

2.3 enter a class

enter image description here

2.4 CTRL drag from storyboard: from the cell's imageView to the @IBOutlet line (from the step 1)

3) Update your cellForItem method:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! PhotoViewCell {

    cell.myImageView.image = imageArray[indexPath.row]
    return cell
}

Upvotes: 0

Soul
Soul

Reputation: 50

use a class for cell , put imageview in your cell make it an outlet

now write this

override func collectionView(collectionView: UICollectionView,      cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! 'your class name for cell'

cell.Image.image = imageArray[indexPath.row]

return cell



}

Upvotes: -1

Related Questions