How to sent imagedata with ImagePicker Controller using swift 4 - ios

I have tabbarController and CameraViewController. I want to show the camera after clicking on camera tab. I have done it. after open the camera i want to show that particular image selected to the next viewController, but unable to do it. i am using UIImagePickerController, please help
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 0 {
//do your stuff
print("First Tab")
} else if tabBarIndex == 1 {
print("Second Tab")
} else if tabBarIndex == 2 {
//do the camera stuff here
let imagePickerController1 = ImagePickerController()
imagePickerController1.delegate = self
imagePickerController1.imageLimit = 2
present(imagePickerController1,animated: true,completion: nil)
print("camera")
print("Third Tab")
}
}
Done button pressed code.
func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
let firstVC = self.storyboard!.instantiateViewController(withIdentifier: "CameraVC") as! CameraVC
show(firstVC, sender: nil)
dismiss(animated: true, completion: nil)
print("done")
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info["UIImagePickerControllerOriginalImage"] as? UIImage {
}
dismiss(animated: true, completion: nil)
}

Your doneButtonDidPress method is implemented in TabBarController and you want selected Images in CameraVC so do 1 thing add NotificationCenter in CameraVC and Post that notification with Images array once you done with Image pick. and load selected images from that array in CameraVC.
CameraVC
NotificationCenter.default.addObserver(self, selector: #selector(updateSelectedImages(_:)), name: NSNotification.Name(rawValue: "updateSelectedImages"), object: nil)
#objc func updateSelectedImages(_ notification: Notification) {
let imagesInfo = notification.object as? NSDictionary
self.arrImages = imagesInfo?.value(forKey: "selectedIamges") as! [UIImage]
self.imageView.image = self.arrImages[0]
self.imageView1.image = self.arrImages[1]
}
UITabBarController
let dict = NSMutableDictionary()
dict.setValue(images, forKey: "selectedIamges")
NotificationCenter.default.post(name: NSNotification.Name("updateSelectedImages"), object: dict)

Related

Trying to add UIImagePicker Moving to different ViewController and view is not in heirachy

What I am trying to do
I am trying to present a UIImagePicker to select an image from the phone's photo library
What is the issue
When I run the code I get this error message:
[Presentation] Attempt to present <UIImagePickerController: 0x160062000> on
<Nebula.SettingsViewController: 0x15f51b3c0> (from <Nebula.SettingsViewController:
0x15f51b3c0>) whose view is not in the window hierarchy.
It also navigates to the first View Controller of my app (even if this hasn't been shown before to the user in this session)
What have I tried to do to fix it
I used this post to try and use the topVC and present from there, this stops the error however still returns me to a different View Controller therefore doesn't allow me to run anymore code from the proper view controller
My code
#IBAction func pickTapped(_ sender: Any) {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.delegate = self
picker.allowsEditing = true
//let topVC = topMostController()
//topVC.present(picker, animated: true)
present(picker, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
print("No image selected")
return
}
guard let imageData = image.pngData() else {
print("Something wrong with image data")
return
}
}
top most VC code
func topMostController() -> UIViewController {
var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
return topController
}

View Controller and displaying another View Controller

I want this.
vc1(performSegue to vc3) -> vc2(For 2 seconds)-dismiss -> vc3
I refer to this.
https://stackoverflow.com/a/39824680/11094223
VC1 CameraViewController
func showVC3() {
performSegue(withIdentifier: "showPhoto_Segue", sender: nil)
}
#IBAction func cameraButton_TouchUpInside(_ sender: Any) {
let settings = AVCapturePhotoSettings()
photoOutput?.capturePhoto(with: settings, delegate: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showLoading_Segue" {
let loadVC = segue.destination as! showLoadingViewController
loadVC.delegate = self
}else if segue.identifier == "showPhoto_Segue" {
let previewVC = segue.destination as! PreviewViewController
previewVC.frameSet = frameSet
previewVC.frameImage = frameImage
previewVC.image = self.image
}
}
extension CameraViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let imageData = photo.fileDataRepresentation() {
image = UIImage(data: imageData)
performSegue(withIdentifier: "showLoading_Segue", sender: nil)
}
}
}
vc2 showLoadingViewController
protocol VC2Delegate {
func showVC3()
}
var delegate: VC2Delegate?
override func viewDidLoad() {
super.viewDidLoad()
let time = DispatchTime.now() + .seconds(2)
DispatchQueue.main.asyncAfter(deadline: time) {
self.showPreview()
}
}
func showPreview(){
dismiss(animated: true, completion: nil)
if let _ = delegate {
delegate?.showVC3()
}
}
vc3 PreviewViewController
If you do this
When moving from vc2 to vc3, vc1 comes out for a while, then goes to vc3.
I want to go straight from vc2 to vc3.(dismiss).
not good at English. I'm sorry
The issue that you are having is because you are animating the dismissal of vc2. Just change it to:
dismiss(animated: false, completion: nil)
if let _ = delegate {
delegate?.showVC3()
}
The animation for showVC3 will play as if it was showing over vc2. vc2 meanwhile will disappear from the stack.

iOS 11 double tap on image dismisses UIImagePickerController and presenter view controller

We have a photo picker made with UIImagePickerController.
When making double tap (instead of one tap) the photo from gallery.
On iOS 10: UIImagePickerController is dismissed
On iOS 11: UIImagePickerController is dismissed and presenting view controller is dismissed as well :0
Is it iOS 11 bug or we have to adjust something?
Our code:
let vc = UIImagePickerController()
vc.delegate = self
vc.modalPresentationStyle = .overFullScreen
vc.allowsEditing = false
rootVC.present(vc, animated: true) // `rootVC` also presented modally.
Instead of self.dismiss(), use picker.dismiss()
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
//self.dismiss(animated: true, completion: nil)
picker.dismiss(animated: true, completion: nil)
}
This will only dismiss your picker view and not the view controller.
We end up with solution: Set delegate = nil right after delegate call in didFinishPickingMediaWithInfo.
public class ImagePicker: NSObject {
private lazy var viewController = setupActionSheet()
private var rootViewController: UIViewController?
private var completionHandler: (([String: Any]) -> Void)?
private var cancellationHandler: (() -> Void)?
}
extension ImagePicker {
public func present(on: UIViewController, completionHandler: #escaping (([String: Any]) -> Void)) {
rootViewController = on
self.completionHandler = completionHandler
cancellationHandler = nil
on.presentAnimated(viewController)
}
public func present(on: UIViewController,
completionHandler: #escaping (([String: Any]) -> Void),
cancellationHandler: #escaping (() -> Void)) {
rootViewController = on
self.completionHandler = completionHandler
self.cancellationHandler = cancellationHandler
on.presentAnimated(viewController)
}
}
extension ImagePicker {
private func setupActionSheet() -> UIAlertController {
let actionSheet = UIAlertController(actionSheetWithTitle: LocalizedString.Generic.ImagePicker.addPhoto)
if UIImagePickerController.isSourceTypeAvailable(.camera) {
actionSheet.addDefaultAction(LocalizedString.Generic.ImagePicker.takePhoto) { [weak self] _ in
self?.presentImagePicker(.camera)
}
}
actionSheet.addDefaultAction(LocalizedString.Generic.ImagePicker.selectPhoto) { [weak self] _ in
self?.presentImagePicker(.photoLibrary)
}
actionSheet.addCancelAction(LocalizedString.Generic.ButtonTitle.cancel) { [weak self] _ in
self?.cancellationHandler?()
}
return actionSheet
}
private func presentImagePicker(_ sourceType: UIImagePickerControllerSourceType) {
let vc = UIImagePickerController()
vc.delegate = self
vc.allowsEditing = false
vc.sourceType = sourceType
rootViewController?.present(vc, animated: true)
}
}
extension ImagePicker: UIImagePickerControllerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
picker.delegate = nil /// It prevents to call delegate when user taps on a few images very fast. seems iOS 11 issue only.
if picker.sourceType == .camera, let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
picker.dismiss(animated: true) {
self.completionHandler?(info)
}
}
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true) {
self.cancellationHandler?()
}
}
}
Usage:
// Somewhere in view controller code.
imagePicker = ImagePicker()
imagePicker?.present(on: self) { [weak self] in
self?.imagePicker = nil
self?.viewModel.addImage($0)
}

Swift 3 - Unable to pass image from one viewcontroller to second [duplicate]

This question already has answers here:
Passing Image to another View Controller (Swift)
(4 answers)
Closed 5 years ago.
i am trying to pass an image from 1st UIViewController to 2nd UIViewControlleler by prepareforSegue
my code :-
extension ViewController:UIImagePickerControllerDelegate,UINavigationControllerDelegate {
func handleImg() {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicer : UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
selectedImageFromPicer = editedImage
} else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
selectedImageFromPicer = originalImage
}
if let selectedImage = selectedImageFromPicer {
imgg.image = selectedImage
}
guard let imageUrl = info["UIImagePickerControllerImageURL"] as? URL else {
return
}
self.performSegue(withIdentifier: "selected", sender: self)
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("canceled picker")
dismiss(animated: true, completion: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "selected" {
let vc = segue.destination as! secondVC
vc.img.image = self.imgg.image
}
}
i am getting the error on line vc.img.image = self.imgg.image
Error
fatal error: unexpectedly found nil while unwrapping an Optional value
You are getting that error because of self.imgg.image is nil. So you are only setting imgg when it is not empty like this:
if let selectedImage = selectedImageFromPicer {
imgg.image = selectedImage
}
but what if this code is never run, then it will throw an error that unexpectedly found nil.
So when you are setting it for second VC, first check if it is not null and then set it like this:
vc.img.image = self.imgg.image
Create variable in secondVC of type UIImage and from your first viewcontroller set image in that variable
You are getting this exception because views of secondVC is not yet created in memory.
So in FirstVC apply following changes
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "selected" {
let vc = segue.destination as! secondVC
vc.image = self.imgg.image
}
}
In secondVC apply following changes
Declare var image: UIImage? = nil
And in viewDidLoad() set image to imageView
override func viewDidLoad() {
super.viewDidLoad()
self.img.image = image
}

Why does my UIImageView replace the second one?

I have two outlets for two different UIImageViews, when I select the first one it'll appear on the first Image View but when I select the second Image, it replaces the first Image View even though it's connected to the second ImageView. This is my code for the Select Image button.
#IBOutlet weak var myImageView1: UIImageView!
#IBOutlet weak var myImageView2: UIImageView!
#IBAction func pickImage1(_ sender: Any) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
}
//Add didFinishPickingMediaWithInfo here
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView1.image = image
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func pickImage2(_ sender: Any) {
let image2 = UIImagePickerController()
image2.delegate = self
image2.sourceType = UIImagePickerControllerSourceType.photoLibrary
image2.allowsEditing = false
self.present(image2, animated: true)
}
//Add didFinishPickingMediaWithInfo here
func imagePickerController2(_ picker2: UIImagePickerController, didFinishPickingMediaWithInfo2 info2: [String : Any]) {
if let image2 = info2[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView2.image = image2
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
Try this code. So you need a flag to remember which image view is clicked, and then set image base on that.
var selected = 1
#IBAction func pickImage1(_ sender: Any) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
selected = 1
self.present(image, animated: true)
}
//Add didFinishPickingMediaWithInfo here
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
if selected == 1 {
myImageView1.image = image
} else {
myImageView2.image = image
}
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func pickImage2(_ sender: Any) {
let image2 = UIImagePickerController()
image2.delegate = self
image2.sourceType = UIImagePickerControllerSourceType.photoLibrary
image2.allowsEditing = false
selected = 2
self.present(image2, animated: true)
}
Moving forward, when you have multiple image views, you can use another method to avoid copying code everywhere.
First, add an unique tag for each image view. Avoid using 0 because the default tag is 0. So you will have image views with tags say 1 to 4.
Call this same method to all your image views so that this function is trigger by clicking on any of them
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
imageView.addGestureRecognizer(tapGestureRecognizer)
Handler looks like this
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
let tappedImage = tapGestureRecognizer.view as! UIImageView
selected = tappedImage.tag
self.present(image, animated: true)
}
Finally in image pick delegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
if let imageView = self.view.viewWithTag(selected) as? UIImageView {
imageView.image = image
}
}
else {
//error
}
self.dismiss(animated: true, completion: nil)
}
The problem is that you have renamed the delegate method. If you do that, the method won't be recognized or called.
Another option to the selected answer is to extend UIImageView and have it adhere to UIImagePickerControllerDelegate / UINavigationControllerDelegate.
extension UIImageView: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
//handle error
return
}
image = selectedImage
picker.presentingViewController?.dismiss(animated: true)
}
func presentImagePicker(from viewController: UIViewController) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
picker.allowsEditing = false
viewController.present(picker, animated: true)
}
}
This is nice because you can then launch the image picker for any UIImageView in your app with one line, like so:
#IBAction func pickImage1(_ sender: UIButton) {
myImageView1.presentImagePicker(from: self)
}

Resources