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