Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS PHImageManager.default().requestImage callback is called twice for the same image

When I try to get an image with specific size, PHImageManager.default().requestImage is called twice with images of different sizes.

Here is the code:

static func load(from asset: PHAsset, targetSize: CGSize? = nil, completion: @escaping (UIImage?)->()) {
        let options = PHImageRequestOptions()
        options.isSynchronous = false
        let id = UUID()
        PHImageManager.default().requestImage(for: asset, targetSize: targetSize ?? PHImageManagerMaximumSize, contentMode: .aspectFill,
                options: options, resultHandler: { image, _ in
            print(id)
            runInMain {
                completion(image)
            }
        })
    }

I added UUID to check if the same UUID is printed twice.

like image 540
Semyon Avatar asked Oct 02 '19 09:10

Semyon


3 Answers

This is because the first callback returns a thumbnail while the full size image is being loaded.

From the official Apple documentation:

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.

like image 187
alxlives Avatar answered Nov 18 '22 10:11

alxlives


Swift 5 It calls only one time with a .deliveryMode = .highQualityFormat

 let manager = PHImageManager.default()
 var imageRequestOptions: PHImageRequestOptions {
        let options = PHImageRequestOptions()
        options.version = .current
        options.resizeMode = .exact
        options.deliveryMode = .highQualityFormat
        options.isNetworkAccessAllowed = true
        options.isSynchronous = true
        return options
    }

  self.manager.requestImage(for: asset,targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: self.imageRequestOptions) { (thumbnail, info) in
         if let img = thumbnail {
             print(img)
          }
    }
like image 37
Gurjinder Singh Avatar answered Nov 18 '22 10:11

Gurjinder Singh


Use: requestOptions.deliveryMode = .highQualityFormat

instead of: requestOptions.deliveryMode = .opportunistic

.opportunistic - Photos automatically provides one or more results in order to balance image quality and responsiveness.

like image 2
Shockki Avatar answered Nov 18 '22 11:11

Shockki