6

I have a UICollectionView with a custom UICollectionViewCell that should get and display thumbnail (low quality) photos from the Photo (usually the user can select more than 1 photo) in each UIImageView in the cell.

I've been playing with the PHImageRequestOptions and their properties, reading about them. To a point that I even passed nil as a parameter for requestImage(for: PHAsset) method because I'm not sure where I'm wrong.

The problem is that the requestImage(for: PHAsset) method is called twice. I need the first time that it's called to just to set the image in each collection view cell with the low quality (thumbnail image) and once the full size image is ready, it should be added in an image array called assetsTurnedIntoImages. The problem is that I'm doing something wrong and I always get the if and the else method called twice, so basically, if I've selected 4 images from the Camera Roll (hence, I have 4 images in the assets array) and when they go through the requestImage(for: asset) method I get 8 images in the assetsTurnedIntoImages instead of 4. So Here's my code

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
        print("Assets count is:", assets.count)
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoPostCVCell", for: indexPath) as! PhotoPostCVCell
        if let takenImage = cameraPhotoUIImage
        {
            cell.cellImage.image = takenImage
        }
        if assets.count > 0
        {
            let asset = assets[indexPath.row]

//            var imageRequestOptions: PHImageRequestOptions
//            {
//                let options = PHImageRequestOptions()
//                //options.version = .current
//                //options.resizeMode = .exact
//                //options.deliveryMode = .fastFormat
//                options.isSynchronous = true
//                return options
//            }
            let targetSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
            imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: nil)
            { (image, info) in
                if image != nil
                {
                    let imageQualityState = info![PHImageResultIsDegradedKey] as! Bool

                    if imageQualityState
                    {
                        print("LOW QUALITY")
                        print("Image Quality State is:", imageQualityState)
                        cell.cellImage.image = image
                        print(image!.size)
                    }
                    else
                    {
                        print(image!.size)
                        cell.cellImage.image = image
                        self.assetsTurnedIntoImages.append(image!)
                    }
                }
            }
        }
        return cell
    }
Dani
  • 3,427
  • 3
  • 28
  • 54

2 Answers2

9

You can discard those low-res duplicates by including this conditional:

imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: nil) { (image, info) in

let isDegraded = (info?[PHImageResultIsDegradedKey] as? Bool) ?? false
if isDegraded {
   return
}
Manu
  • 91
  • 1
  • 4
1

Affraid there is not much you can do about requestImage:forAsset being called twice. However, you can change how you are putting images in the array to avoid duplicates. Might I suggest:

self.assetsTurnedIntoImages[indexPath.row] = image

This will cause the image passed into completion the second time around to replace the one that was called the first time, avoiding duplication.

You will want to pre-initialize enough space for your array ahead of time so that indexPath.row does not try to access your array out of bounds. In ViewDidLoad add something to the effect of:

self.assetsTurnedIntoImages = [UIImage](repeating: UIImage(), count: assets.count)
NSGangster
  • 2,397
  • 12
  • 22
  • I get a crash though. I get an error `fatal error: Array index is out of range` – Dani Sep 20 '17 at 14:45
  • hmmm they must not be getting called in order, lets say the `requestImage` gets called at image 3 before it does at image 1. I will update my answer. – NSGangster Sep 20 '17 at 14:48
  • I did as you suggested, but the `assetsTurnedIntoImages ` now has triple the amounts of images in it. If I have picked 4 assess from Photos, I get 12 images in the array. – Dani Sep 20 '17 at 14:54
  • Do you have 12 assets? What is `assets.count` in `ViewDidLoad`? – NSGangster Sep 20 '17 at 15:03
  • No, it's 4. This is why it's so baffling. I don't get why they've tripled now. – Dani Sep 20 '17 at 15:06
  • Changed answer, we should assign the image at said index instead of insert. My apologies. – NSGangster Sep 20 '17 at 15:11
  • OMG, this actually worked. I've been struggling with this for a week! Thank you so much for your help! – Dani Sep 20 '17 at 15:16