0

Had this working on the last few versions of iOS but on 14 cannot get this to work, I have spent the past 5 days Googling.

Whenever I go to add an image from the gallery the popup to select an image is blank.

I have tried UIImagePickerController(which works fine iOS13 and below) and the new PHPickerViewController.

What has been working up until iOS14 is the user clicks a bar button to "add image" and the pop up asks to pick from the gallery and then presents the picker with images in your gallery.

I have set the Info.plist "Privacy - Photo Library Usage Description" for UIImagePickerController, I know the PHPickerViewController doesn't need perms as it handles getting the image for you.

I have also been seeing these purple warning now and again saying "xxxx must be used from main thread only", never seen that before until the new Xcode.

Any help would be much appreciated. Running Xcode 12.0.1 (12A7300), simulators running iOS14.

Adam

enter image description here

enter image description here

enter image description here

class AddCustomExerciseViewController: UIViewController, UITextViewDelegate, UINavigationControllerDelegate, GADBannerViewDelegate, UIImagePickerControllerDelegate, PHPickerViewControllerDelegate{

let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in self.openGallery() }))
        alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
        self.present(alert, animated: true, completion: nil)

func openGallery()
{
    let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
        switch photoAuthorizationStatus {
        case .authorized:
            self.showGallery()
            print("Access is granted by user")
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization({
                (newStatus) in
                print("status is \(newStatus)")
                if newStatus ==  PHAuthorizationStatus.authorized {
                    self.showGallery()
                    print("success")
                }
            })
            print("It is not determined until now")
        case .restricted:
            // same same
            print("User do not have access to photo album.")
        case .denied:
            // same same
            print("User has denied the permission.")
        case .limited:
            // same same
            print("User has denied the permission.")
        }
}

func showGallery()
{
    if #available(iOS 14, *)
    {
        var configuration = PHPickerConfiguration()
        configuration.filter = .images
        configuration.selectionLimit = 0
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        self.present(picker, animated: true, completion: nil)
    }
    else
    {
                
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.allowsEditing = false
            imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
            self.present(imagePicker, animated: true, completion: nil)
        }
        else
        {
            let alert  = UIAlertController(title: "Warning", message: "You don't have permission to access gallery.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
        
        //get the file url
        if let fileUrl = info[UIImagePickerControllerImageURL] as? URL {
            print(fileUrl)
            print(fileUrl.lastPathComponent)
            let filePath = fileUrl.lastPathComponent
            
            if(filePath.hasSuffix("GIF")||filePath.hasSuffix("gif"))
            {
                //to change later to support gifs
                gifView.image = pickedImage
            }
            else
            {
                //to show the static image to users
                gifView.image = pickedImage
            }
            //for saving the file name to retrieve in local parse datastore
            imageNameToSave = fileUrl.lastPathComponent
        }
        //for saving the selected image
        imageToSave = pickedImage
    }
    picker.dismiss(animated: true, completion: nil)
}
@available(iOS 14, *)
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
{
   picker.dismiss(animated: true, completion: nil)
   for result in results
   {
      result.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: { (object, error) in
         if let image = object as? UIImage {
            DispatchQueue.main.async {
               // Use UIImage
               print("Selected image: \(image)")
            }
         }
      })
   }
}  }
Adam First
  • 435
  • 1
  • 4
  • 19
  • Hi Adam, Did you find any solution for same? i had almost same issue, i can get the list of images but i can not able to select and get error as ` -[NSURL URLByAppendingPathExtension:]: component, components, or pathExtension cannot be nil.` – Hindu Jan 15 '21 at 10:39
  • Hi @Hindu, I wrote in response to an answer that it just appears to be the simulator with a bug. I tried it on a couple of real iOS devices and the gallery opened and I could select an image fine. – Adam First Feb 04 '21 at 00:42
  • Has anyone found a solution to this? I am having the same problem. Both the UIPickerViewController and PHPickerViewController present with iOS14 and will show the photo albums in the album view, but even if you select an album no photos will show up in the photo selection view. Tried on my iPhone as well and doesn't work. – Azure May 29 '21 at 00:03

2 Answers2

1

On iOS 14 the restricted image picker permission dialog opens in a separate thread, so when the authorization return you will need to perform UI tasks on main thread.

PHPhotoLibrary.requestAuthorization({
        (newStatus) in
    DispatchQueue.main.async {
        print("status is \(newStatus)")
        if newStatus ==  PHAuthorizationStatus.authorized {
            self.showGallery()
            print("success")
        }
    }
})
Mohit Padalia
  • 1,549
  • 13
  • 10
  • Thanks, I have added DispatchQueue.main.async { } like you have shown above, which gets rid of the purple warnings and does run on the main thread, but I still can't browse the photo gallery. – Adam First Sep 29 '20 at 11:58
  • Why is configuration.selectionLimit = 0, this is the number of photos one can select at a time, can you try with configuration.selectionLimit = 1 – Mohit Padalia Oct 01 '20 at 11:29
  • selectionLimit = 0 equals unlimited selection. I did try = 1 but made no difference. See here: https://mackuba.eu/2020/07/07/photo-library-changes-ios-14/ Subsequently I have done some testing on real iOS14 devices and my above code is working perfectly fine, it just seems to be in the simulator. I released the update to the app store and have been trying on friends devices, all working. https://www.gymexercisesapp.com/ – Adam First Oct 03 '20 at 06:40
1

If this is helpful for anyone else I discovered that editing the scrollview appearance proxy background caused a bug in both the UIImagePickerController and the PHPickerViewController preventing them from showing images in iOS 14 and above. I had edited the scrollview background proxy because it is black even in light mode. After hours of googling and testing I discovered that removing the appearance background modification on the scrollview proxy allowed the image pickers to function as expected. I filed a bug report with Apple. The line of code that caused the bug was:

UIScrollView.appearance().backgroundColor = .systemBackground
Azure
  • 229
  • 2
  • 5