PHCachingImageManager.requestImage is always called twice?

Viewed 2131

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
    }
2 Answers

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
}

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)
Related