Jeff Zhang
Jeff Zhang

Reputation: 140

UIImagePickerControllerDelegate didFinishPickingMediaWithInfo not called

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)
    }
}

Upvotes: 1

Views: 1021

Answers (1)

Jeff Zhang
Jeff Zhang

Reputation: 140

This question is duplicated. It is actually not an ImagePicker problem, and it is more like a protocol extension problem. The reason is swift protocol cannot extend objc protocol.

I think I've already given the solution and explanation in my question.

Explanations:

  1. Swift protocol implementing another @objc protocol

  2. Non-'@objc' method does not satisfy optional requirement of '@objc' protocol

Solution: https://gist.github.com/rpassis/4622291029cd12e4ce2b7585d3e62d15

I will change my code by following the solution above, if you have any new idea, please reply me. Thanks a lot.

Upvotes: 1

Related Questions