Reputation: 866
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.
Upvotes: 4
Views: 789
Reputation: 437592
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
}
}
Upvotes: 4
Reputation: 4855
Try using Function as Below
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "segue"
{
if let xferVC = segue.destination as? XferImageViewController {
xferVC.storedImage = pickedImage.image
//Why Optional here ?
//xferVC?.storedImage = pickedImage.image
}
}
}
Upvotes: 0