3

I am using PHPickerViewController to pick Image for User Profile Picture Purpose in iOS 15. I am using UIKit framework. I have the following code:

var pickerConfig = PHPickerConfiguration(photoLibrary: .shared())
pickerConfig.selectionLimit = 1
pickerConfig.filter = .images
let pickerView = PHPickerViewController(configuration: pickerConfig)
pickerView.delegate = self
self.present(pickerView, animated: true)

The Picker is working properly for selecting images and delegating the results. But, when the Cancel button is pressed, nothing happens and the Picker is not dismissed as expected.

How to dismiss the PHPickerViewController instance when its own Cancel button is pressed ?

Edit:

The implementation of PHPickerViewControllerDelegate Method is as follows:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
    {
        results.first?.itemProvider.loadObject(ofClass: UIImage.self) { [unowned self] reading , error in
            guard let image = reading as? UIImage, error == nil else
            {
                DispatchQueue.main.async {
                    picker.dismiss(animated: true)
                    self.profilePictureHasError = true
                    self.toggleDoneButtonEnabled()
                }
                return
            }
            self.profilePictureHasError = false
            DispatchQueue.main.async {
                picker.dismiss(animated: true)
                self.profilePictureHasChanged = self.userProfilePicture != image
                if self.profilePictureHasChanged
                {
                    self.profilePictureView.image = image
                    self.toggleDoneButtonEnabled()
                }
            }
        }
    }
Kris2k
  • 275
  • 2
  • 12

2 Answers2

7

You need to dismiss the picker yourself in the picker(_:didFinishPicking:) delegate method which is called when the user completes a selection or when they tap the cancel button.

From the Apple docs for picker(_:didFinishPicking:):

The system doesn’t automatically dismiss the picker after calling this method.

For example:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    // Do something with the results here
    picker.dismiss(animated: true)
}

Your current delegate code only calls picker.dismiss when the results array is non-empty (i.e when the user has selected images). When the cancel button is tapped, the delegate method is called with an empty results array.

Fix the issue by adding the following to the top of the code in your delegate method:

if results.isEmpty {
    picker.dismiss(animated: true)
    return
}
samaitch
  • 1,172
  • 7
  • 9
  • I have done this already. My problem is that the "Cancel" button shown on the picker is not working. – Kris2k Jul 14 '22 at 09:02
  • Can you add the code in your `picker(_:didFinishPicking:)` delegate method to your question? This method is also called when the cancel button is pressed (just with an empty results array). – samaitch Jul 14 '22 at 09:55
  • 1
    I have updated the answer. The current code in your delegate method only calls dismiss when the results array is non-empty, you also need to call dismiss when the results array is empty, which is the case when the user taps cancel. – samaitch Jul 14 '22 at 10:06
0

you just wrap it out in an objc func for making cancel button works

    @objc
    func didOpenPhotos() {
        lazy var pickerConfig = PHPickerConfiguration()
        pickerConfig.filter = .images
        pickerConfig.selectionLimit = 1
        let pickerView = PHPickerViewController(configuration: pickerConfig)
        pickerView.delegate = self
        self.present(pickerView, animated: true)
    }

call it anywhere

Zeeshan Ahmad II
  • 1,047
  • 1
  • 5
  • 9
  • It is not working still :-( – Kris2k Jul 14 '22 at 09:05
  • call it with a delay if you calling it in viewdidload then add some mili seconds delay DispatachQueue.main.asyncAfter(deadline: .now() + 0.1) { didOpenPhotos() } – Zeeshan Ahmad II Jul 14 '22 at 09:09
  • I am calling it when an `UIImageView` is tapped. I am using `UITapGestureRecognizer` for recognizing taps on `UIImageView` and the `Selector` is already an `@objc` function. – Kris2k Jul 14 '22 at 09:29
  • why image view? why not you just using a button with UIImage ? – Zeeshan Ahmad II Jul 14 '22 at 09:40
  • I am using it for displaying profile picture of user. when the user clicks on it, he/she can change the profile picture by means of `PHPickerViewController` – Kris2k Jul 14 '22 at 09:46
  • you can also use UIButton here and set image button.setImage() property also change the content mode of button image view button.imageView.contentMode = .scaleAspectFill – Zeeshan Ahmad II Jul 14 '22 at 10:32