What is the difference between segue and instantiateViewController?
I've been trying to figure out how to use segues to send an image from one view controller to another and 2 answers (Passing Image to another View Controller (Swift) and How do I segue an image to another ViewController and display it within an ImageView?) both say to use segues but when trying to use segues I encountered a few problems like the second view controller not showing up after the photo library dismissed or that the image was not showing up.
Segue example
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is XferImageViewController {
print("Test: ", pickedImage.image)
let xferVC = segue.destination as? XferImageViewController
xferVC?.storedImage = pickedImage.image
}
print("WHAT IS GOING ON")
// if segue.destination is XferImageViewController {
// let xferVC = segue.destination as? XferImageViewController
// print(pickedImage.image)
// //xferVC?.storedImage = pickedImage.image
// xferVC?.storedImage = pickedImageVar
// }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
pickedImage.image = image
} else {
print("Something went wrong")
}
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
dismiss(animated:true, completion: nil)
performSegue(withIdentifier: "xferImage", sender: self)
}
InstantiateViewController Example
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
pickedImage.image = image
} else {
print("Something went wrong")
}
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
dismiss(animated:true, completion: nil)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "xferImage") as! XferImageViewController
controller.storedImage = image
present(controller, animated: true, completion: nil)
}
So after using InstantiateViewController instead of segue I got the results that I wanted. What is the difference between the two? (I made sure that that segue identifier, tried segue.destination and storyboard ID but still wasn't getting what I needed) It is possible that I don't know how to use segue after the photo library dismiss call but still want to know the difference.
The issue is that the segue is particular about the state of the view controller hierarchy when you initiate the segue. You have to defer the performSegue(withIdentifier:sender:)
until the dismiss
is done, namely put it into the completion handle of dismiss
:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
pickedImage.image = image
} else {
print("Something went wrong")
}
dismiss(animated: true) {
self.performSegue(withIdentifier: "xferImage", sender: self)
}
}
The above worked fine for me.
BTW, you can simplify your prepare(for:sender:)
implementation:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let xferVC = segue.destination as? XferImageViewController {
xferVC.storedImage = pickedImage.image
}
}
Two somewhat unrelated observations:
If pickedImage
is an image view, I'd suggest renaming it (and updating the outlets in your storyboard) to pickedImageView
. It's a good convention to avoid confusion between UIImage
properties and UIImageView
outlets.
This is an even more minor observation, but in Model-View-Controller design, you generally don't want to rely on UIKit objects, like UIImageView
to hold model objects, namely the selected image. It suggests a conceptual confusion between "view" objects and "model" objects. Plus, what if the current view controller didn't have a UIImageView
?
I'd personally suggest storing the selected image in a separate UIImage?
property:
private var selectedImage: UIImage?
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
selectedImage = image
// if you also want to update a `UIImageView` in the current
// view controller, fine, do that, but it shouldn't be confused
// with the "model".
//
// pickedImageView.image = image
} else {
print("Something went wrong")
}
dismiss(animated: true) {
self.performSegue(withIdentifier: "xferImage", sender: self)
}
}
And:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let xferVC = segue.destination as? XferImageViewController {
xferVC.storedImage = selectedImage
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With