Search code examples
iosswiftphotokit

PhotoKit requestImage returns low res images?


When fetching images and video with Photo Kit my images and video thumbnails are displaying in low res within my LazyVGrid.

They also display in lo-res when I display the image inside a larger Image view.

All of my images and video are stored on iCloud so I set isNetworkAccessAllowed = true AND deliveryMode = .highQualityFormat in PHImageRequestOptions().

I have tried changing the targetSize in the requestImage method to different values but that didn't change the quality either.

What am I doing wrong?

   @Published var fetchedMediaArray : [MediaAsset] = []

   // model for Assets
   struct MediaAsset: Identifiable, Hashable {
     var id = UUID()
     var image : UIImage
     var selected: Bool
     var asset: PHAsset
   }

   func requestAuth() {/*auth code*/ }

   func fetchPhotosAndVideos() { 
        let opt = PHFetchOptions()
        opt.includeHiddenAssets = false
        opt.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        opt.predicate = NSPredicate(format: "mediaType == %d || mediaType == %d",
                                             PHAssetMediaType.image.rawValue,
                                             PHAssetMediaType.video.rawValue)
        let req = PHAsset.fetchAssets(with: opt)
        
        DispatchQueue.main.async {
            let options = PHImageRequestOptions()
            options.isSynchronous = true
            options.deliveryMode = .highQualityFormat
            options.isNetworkAccessAllowed = true
            for j in 0..<req.count {
                
                PHCachingImageManager.default().requestImage(for: req[j], targetSize: CGSize(width: 100, height: 100), contentMode: .default, options: options) { (image, _) in
                    let data1 = MediaAsset(image: image!, selected: false, asset: req[j])
                    self.fetchedMediaArray.append(data1)
                   
                 }
             }
         }
     }


Solution

  • When Photos are being downloaded from cloud, it may call your completion handler multiple times.

    From the PHImageManager.requestImage(for:asset) docs -

    Discussion

    For an asynchronous request, Photos may call your result handler block more than once. Photos first calls the block to provide a low-quality image suitable for displaying temporarily while it prepares a high-quality image. (If low-quality image data is immediately available, the first call may occur before the method returns.) When the high-quality image is ready, Photos calls your result handler again to provide it. If the image manager has already cached the requested image at full quality, Photos calls your result handler only once. The PHImageResultIsDegradedKey key in the result handler’s info parameter indicates when Photos is providing a temporary low-quality image.

    What you can do in your callback handler -

    1. If your asset is being returned in target/requested size(or bigger than requested), you can consider it done.
    2. If your asset is being returned in smaller than target/requested size, you should check for PHImageResultIsDegradedKey in the info parameter and wait for Photos to call your completion next time.