I have a project which has many viewControllers using imagePicker. For each time, I have to copy the didFinishPickingMediaWithInfo again and only change some code.
Then I decided to wrap the UIImagePickerControllerDelegate and UINavigationControllerDelegate into my own protocol and extend this protocol to achieve didFinishPickingMediaWithInfo. However, the didFinishPickingMediaWithInfo is not being called at all. All the other parts work well, the image picker and camera view show well, but after finish picking, the didFinish function not being called.
I saw few suggestions online, like this one. They use the concrete class to warp the two protocols, instead of the interface.
https://gist.github.com/rpassis/4622291029cd12e4ce2b7585d3e62d15
I don't know why my solution is wrong, could someone tell me the reason why my code is wrong. Maybe I misunderstand some parts of protocol and protocol extension. BTW, I find out one warning which is
Non-'@objc' method 'imagePickerController(_:didFinishPickingMediaWithInfo:)' does not satisfy optional requirement of '@objc' protocol 'UIImagePickerControllerDelegate'
Another explanation is from Swift protocol implementing another @objc protocol
My code is shown below.
public protocol ImagePickerDelegate: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    func successActionFromCamera(with localIdentifier: String, picker: UIImagePickerController)
    func successActionFromPhotoLibrary(with imageURL: URL, picker: UIImagePickerController)
}
Extension to my custom Delegate
extension ImagePickerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    //camera
    if info[UIImagePickerControllerReferenceURL] == nil {
        func savePhotoAndTakeAction() {
            var imagePlaceholder:PHObjectPlaceholder!
            DispatchQueue.global(qos: .default).async {
                PHPhotoLibrary.shared().performChanges({
                    let request = PHAssetChangeRequest.creationRequestForAsset(from: info[UIImagePickerControllerOriginalImage]! as! UIImage)
                    imagePlaceholder = request.placeholderForCreatedAsset!
                }, completionHandler: { (success, error) -> Void in
                    DispatchQueue.main.async {
                        if success {
                            //image saved to photos library.
                            self.successActionFromCamera(with: imagePlaceholder.localIdentifier, picker: picker)
                        } else {
                            picker.dismiss(animated: true, completion: nil)
                            print(error!.localizedDescription)
                        }
                        picker.dismiss(animated: true, completion: nil)
                    }
                })
            }
        }
        switch PHPhotoLibrary.authorizationStatus() {
        case .denied:
            picker.dismiss(animated: false) { BasePhotoUtil.showAccessAlertController(false) }
            return
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization({ (newStatus) in
                if (newStatus == .authorized) {
                    savePhotoAndTakeAction()
                }
                else {
                    DispatchQueue.main.async {
                        picker.dismiss(animated: false, completion: { BasePhotoUtil.showAccessAlertController(false) })
                    }
                    return
                }
            })
        default:
            break
        }
        savePhotoAndTakeAction()
    } else {
        //photo library
        if let imageURL = info[UIImagePickerControllerReferenceURL] as? URL {
            self.successActionFromPhotoLibrary(with: imageURL, picker: picker)
        } else {
            picker.dismiss(animated: true, completion: nil)
        }
    }
}
The function to present ImagePicker
private static func showImagePickerView(isCamera: Bool, currentVC: UIViewController) {
    let imagePicker = UIImagePickerController()
    imagePicker.delegate = currentVC as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
    imagePicker.allowsEditing = false
    imagePicker.navigationBar.isTranslucent = false
    if isCamera {
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            imagePicker.sourceType = .camera
            imagePicker.cameraCaptureMode = .photo
        } else {
            BaseAlertUtil.showNoFunctionAlertController(title: "No Camera", message: "Sorry, this device has no camera")
        }
    } else {
        imagePicker.sourceType = .photoLibrary
    }
    currentVC.present(imagePicker, animated: true) {
        BaseThemeUtil.setStatusBarStyle(.default)
    }
}
