Can I set the order of the images? PHPickerViewController

1k views Asked by At

Using the PHPickerViewController, the result of the selected image will be displayed as a result. Can I set the order of the images?

private func makePickerViewController(selectionLimit: Int) -> PHPickerViewController {
    var config = PHPickerConfiguration()
    config.selectionLimit = selectionLimit
    config.filter = PHPickerFilter.images
    
    let pickerViewController =  PHPickerViewController(configuration: config)
    return pickerViewController
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    
    picker.dismiss(animated: true, completion: nil)
    
    for (index, result) in results.enumerated() {
        let itemProvider = result.itemProvider
        if itemProvider.canLoadObject(ofClass: UIImage.self)  {
            itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { (url, error) in
                // How can you determine the order of the selected images?
            }
        }
    }
}

enter image description here

For example, if the user selects it as in the picture above, the order in which it goes to the results should be the same.

1

There are 1 answers

0
C6Silver On

You can do this pretty readily without an external library.

func makeUIViewController(context: Context) -> PHPickerViewController {
        var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
        config.filter = .images
        config.selection = .ordered
        config.selectionLimit = 0
        let picker = PHPickerViewController(configuration: config)
        picker.delegate = context.coordinator
        return picker
    }

Using selectionLimit of 0 sets it so that a number is shown when the user taps on a photo. This number cooresponds to the order in which they tapped.

class Coordinator: NSObject, PHPickerViewControllerDelegate {
    let parent:ImagePicker
    
    init(_ parent:ImagePicker) {
        self.parent = parent
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        
        let group = DispatchGroup()
        var images = [UIImage]()
        var order = [String]()
        var asyncDict = [String:UIImage]()
        
        for result in results {
            order.append(result.assetIdentifier ?? "")
            group.enter()
            let provider = result.itemProvider
            if provider.canLoadObject(ofClass: UIImage.self) {
                provider.loadObject(ofClass: UIImage.self) { image, _ in
                    guard let updatedImage = image as? UIImage else {group.leave();return}
                    asyncDict[result.assetIdentifier ?? ""] = updatedImage
                    group.leave()
                }
            }
        }
        group.notify(queue: .main) {
            for id in order {
                images.append(asyncDict[id]!)
            }
            self.parent.images = images
        }
    }
}

Since the process to retrieve the photo is asynchronous, the results can be returned in any order. It does not appear that Apple provides any additional property that carries the user's order selection with it. As a result we need to tag the returned images ourselves and then re-assembly them in order into the final array.

We can make use of the assetIdentifier which is exposed to us if we set our configuration using var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared()) Please note that leaving out the photoLibrary parameter will prevent us from getting the assetIdentifier, so make sure to use that instantiation!

We then store each image as it's returned into a dictionary which will have the assetIdentifier as its key. Just prior to making the async request for the image we will store the assetIdentifier into an array which will give us the intended order that the user selected.

Finally, when all async requests are completed, we reassemble the images into the ordered array by getting the ordered keys and accessing our dictionary with those same keys providing the corresponding image.