Search code examples
iosswifticloudphasset

Fetch Images From ICloud Will Freeze The UI


I'm using BSImagePicker lib for choosing multiple images in my App, when user select Images stored on ICloud only the UI will freeze up on the images picker controller until the images are downloaded I tried to fix it but with no results

Here is my code :

Choosing the images and show them in slider

 @IBAction func choose_images(_ sender: Any) {

        bs_presentImagePickerController(vc, animated: true,
                                        select: { (asset: PHAsset) -> Void in
                                            // User selected an asset.
                                            // Do something with it, start upload perhaps?
        }, deselect: { (asset: PHAsset) -> Void in
            // User deselected an assets.
            // Do something, cancel upload?
        }, cancel: { (assets: [PHAsset]) -> Void in

        }, finish: { (assets: [PHAsset]) -> Void in
            // User finished with these assets

            // print(assets.count)

            DispatchQueue.main.async{
                self.imagesource.removeAll()
                self.imagesdata.removeAll()
                for img in assets{

                    self.imagesource.append(ImageSource(image:  self.getUIImage(asset: img)!))
                    self.imagesdata.append(self.getUIImage(asset: img)!)
                }

                self.slider.setImageInputs(self.imagesource)
                self.slider.contentScaleMode = UIViewContentMode.scaleAspectFill
                self.slider.slideshowInterval = 2
                self.slider.zoomEnabled = true
                self.slider.backgroundColor = UIColor.black
                self.slider.pageControlPosition = PageControlPosition.insideScrollView
                let recognizer = UITapGestureRecognizer(target: self, action: #selector(self.didTap))
                self.slider.addGestureRecognizer(recognizer)
            }
        }, completion: nil)


    }

Function to return the image for chosen assets

func getUIImage(asset: PHAsset) -> UIImage? {

        var img: UIImage?
        let manager = PHImageManager.default()
        let options = PHImageRequestOptions()
        options.version = .original
        options.isNetworkAccessAllowed = true
        options.isSynchronous = true
        options.progressHandler = { (progress, error, stop, info) in
            if(progress == 1.0){
                SVProgressHUD.dismiss()
            } else {

                SVProgressHUD.showProgress(Float(progress), status: "Downloading from iCloud")

            }
        }
        manager.requestImage(for: asset, targetSize:PHImageManagerMaximumSize, contentMode: PHImageContentMode.aspectFit, options: options) { (image, info) in

            img = image
        }

        return img
    }

Any Help will be much appreciated


Solution

  • Your primary issue is that you are synchronously accessing the remote images on the main queue. You need to perform your loop in the background.

    You need to update the code in your finish block as follows:

    }, finish: { (assets: [PHAsset]) -> Void in
        DispatchQueue.global().async {
            self.imagesource.removeAll()
            self.imagesdata.removeAll()
            for img in assets {
                if let res = getUIImage(asset: img) {
                    self.imagesource.append(ImageSource(image: res))
                    self.imagesdata.append(res)
                }
            }
    
            DispatchQueue.main.async {
                self.slider.setImageInputs(self.imagesource)
                self.slider.contentScaleMode = UIViewContentMode.scaleAspectFill
                self.slider.slideshowInterval = 2
                self.slider.zoomEnabled = true
                self.slider.backgroundColor = UIColor.black
                self.slider.pageControlPosition = PageControlPosition.insideScrollView
                let recognizer = UITapGestureRecognizer(target: self, action: #selector(self.didTap))
                self.slider.addGestureRecognizer(recognizer)
            }
        }
    

    You may also have to update the progress handler inside getUIImage to update the SVProgressHUD on the main queue.

    Note that with the above code you should keep your getUIImage as-is except for the one change I just mentioned.