Search code examples
iosswiftswift2phasset

Fetching thumbnails from PHAsset


I'm trying to fetch thumbnail as well as some other information from PHAsset. Here is a simplified code snippet.

For all the images I retrieve from camera roll do:

static func fetchAsset(asset: PHAsset)
{
        if(asset.mediaType == PHAssetMediaType.Image){
            let screenScale: CGFloat = UIScreen.mainScreen().scale
            let imageSize = CGSize(width: 100 * screenScale, height: 100 * screenScale)

            let options: PHImageRequestOptions = PHImageRequestOptions()
            options.deliveryMode = PHImageRequestOptionsDeliveryMode.FastFormat
            options.resizeMode = PHImageRequestOptionsResizeMode.Fast
            options.synchronous = false

            PHImageManager.defaultManager().requestImageForAsset(asset,
                targetSize: imageSize,
                contentMode: PHImageContentMode.AspectFill,
                options: options,
                resultHandler: { (result, info) -> Void in
                    if (result != nil && result!.scale == screenScale) {

                        var newItemImage = MyImage(isLocal:true)
                        if let fname = asset.valueForKey("filename") as? String{
                            newItemImage.fileName = fname
                        }
                        newItemImage.thumbnail = result
                        asset.requestContentEditingInputWithOptions(PHContentEditingInputRequestOptions()) { (contentEditingInput, info) -> Void in

                            //Get full image
                            let url = contentEditingInput!.fullSizeImageURL

                            newItemImage.url = url
                        }
                        //DO SOMWTHING WITH IMAGE
                    }else
                    {
                        //DO SOMWTHING ELSE
                    }
            })
        }
    }

I've got two problems at this stage:

  1. The most important one but I guess it's consequent. It takes too much of processing power and reading from the disc. It works fine in emulator. But when I run it on test device (iPhone 5, 4S), which have 300-500 images, it freezes for a minute or two, while getting all the images. I guess it reads through whole collection one by one, resizes it and fetches all this information. Is there are simpler way? Like it was possible with ALAsset, I could just get thumbnail directly and it was flying fast.
  2. It does the job twice for some reason. First it gives me what I had asked for, small thumbnails ~ 60 * 40 or around that. Once it gave me that, after a couple of seconds it goes for another loop and starts to retrieve higher resolution images, like 960 * 640 or so, and that's where freezing is happening. I'm not sure why this is happening but it does.

Any input on these two problems will be highly appreciated.


Solution

  • It does the job twice for some reason

    Because that's what it's supposed to do. Fetching images from the photo library takes time, as you've discovered. Therefore, the default behavior is we supply a low-resolution image as quickly as possible, just so you have something to display; we then call again, possibly several times, with better-quality versions of the image. Moreover, the fetch is being formed asynchronously. Thus, it is perfectly possible to end up with multiple fetch requests happening at once, which can cause your code to start stumbling over its own feet, as you've discovered.

    If you don't like that, set the fetch options synchronous to true — but then you must make this whole call on a background queue! By doing this in a serial queue you can make sure that the calls are performed separately in turn, and each image will be delivered just once. Moreover, then (and only then) your PHImageRequestOptions.DeliveryModeFastFormat will be obeyed. Don't forget to step back out to the main thread before doing anything with the image you receive!