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

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
}

Related

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.

Capture a still image from a video and add to a image view in separate viewcontroller Swift [duplicate]

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 5 years ago.
I am trying to get a thumbnail from a video chosen from the image-picker and add the thumbnail into a UIImageView in a separate view-controller however, I am getting the error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value in the second view controller
I know what the error means I just don't understand why the thumbnail isn't being passed to the next view controller in the UIImageView
Here is my code for the first view controller.
#IBAction func upload(_ sender: Any) {
let pickerController = UIImagePickerController()
pickerController.delegate = self
pickerController.mediaTypes = ["public.movie"]
present(pickerController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let videoUrl = info[UIImagePickerControllerMediaURL] as? URL {
self.vidurl = videoUrl
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toupload" {
let uploadvc = segue.destination as! UploadVC
uploadvc.videourl = vidurl
}
}
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage{
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toupload" {
let uploadvc = segue.destination as! UploadVC
uploadvc.previewImage.image = image
}
}
}
performSegue(withIdentifier: "toupload", sender: nil)
}
dismiss(animated: true, completion: nil)
}
here is the code for the second view-controller
#IBOutlet weak var previewImage: UIImageView!
var videourl: URL?
override func viewDidLoad() {
super.viewDidLoad()
previewImage.image = thumbnailImageForFileUrl(videourl!) Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
}
func thumbnailImageForFileUrl(_ fileUrl: URL) -> UIImage? {
let asset = AVAsset(url: fileUrl)
let imageGenerator = AVAssetImageGenerator(asset: asset)
do {
let thumbnailCGImage = try imageGenerator.copyCGImage(at: CMTimeMake(7, 1), actualTime: nil)
return UIImage(cgImage: thumbnailCGImage)
} catch let err {
print(err)
}
return nil
}
Currently you're nesting prepareForSegue function inside the callback of the picker so remove it and declare it inside the scope of the view controller so when you call performSegue the videoUrl of the class is assigned to the videUrl of the secondVC resulting in non-nil. This should be out and call performSegue
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let videoUrl = info[UIImagePickerControllerMediaURL] as? URL {
self.vidurl = videoUrl
}
else
{
}
performSegue(withIdentifier: "toupload", sender: nil)
}
///
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toupload" {
let uploadvc = segue.destination as! UploadVC
uploadvc.videourl = vidurl
}
}

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

How do i save and recall a UIImage on the View Controller?

I am using Swift 3 and have been following apples https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson4.html have created 20 different UIImage views on 20 different UIViewcontroller
They are called photoImageView1 photoImageView2 etc. currently you are able to click on each generic image and input your own image.
I would like the user to be able to input their image but also save it and when they re-open that same viewcontroller the image they inputed is there.
I have looked at many different methods however have been unsuccessful i have attempted following this question Save images in NSUserDefaults? and was once again unsuccessful. Any help would be much appreciated, Thanks.
i ended up using this method it may not be the best but its easy and it works.
import UIKit
class timetable: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
#IBOutlet var imageviewtimetable: UIImageView!
#IBAction func saveMyImage(_ sender: UIBarButtonItem) {
let myTimeTableImage = imageviewtimetable.image
let theImageData:NSData = UIImagePNGRepresentation(myTimeTableImage!)! as NSData
UserDefaults.standard.set(theImageData, forKey: "mySavedImage")
let data = UserDefaults.standard.object(forKey: "mySavedImage")
imageviewtimetable.image = UIImage(data: data as! Data)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let data = UserDefaults.standard.object(forKey: "mySavedImage")
imageviewtimetable.image = UIImage(data: data as! Data)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func selectImageFromPhotoLibrary(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
dismiss(animated: true, completion:nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
imageviewtimetable.image = selectedImage
dismiss(animated: true,completion:nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
You can store the image name in a database, iCloud, a plist or even Userdefaults. To save an image to disk, but not the photo library, use:
import PlaygroundSupport
import UIKit
func save(image: UIImage, name: String) -> Bool {
guard var path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first,
let imageData = UIImagePNGRepresentation(image) else {
return false
}
path = path.appendingPathComponent(name)
do {
try imageData.write(to: path)
} catch {
return false
}
return true
}
func loadImage(name: String) -> UIImage? {
guard var path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return nil
}
path = path.appendingPathComponent(name)
return UIImage(contentsOfFile: path.relativePath)
}
let image = UIImage(named: "test.png")!
save(image: image, name: "test2.png")
let loadedImage = loadImage(name: "test2.png")
PlaygroundPage.current.liveView = UIImageView(image: loadedImage)
EDIT: I changed the source code to a full playground so you can copy and paste it into a playground and run it. The only thing you need to do is drag a file named test.png into the Resources folder.

How to send UIImage from didFinishPickingMediaWithInfo with Segue?

So what I have:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info:[String : Any]) {
let tempImage: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
let imagetoTransmit: UIImage = tempImage
shootedImage = imagetoTransmit
self.performSegue(withIdentifier: "cameraSegueIdent", sender: nil)
dismiss(animated: true, completion: nil)
}
where Segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "cameraSegueIdent" {
let imageToTransmit: UIImage = shootedImage
let viewController = (segue.destination as! TakenPhotoPreviewViewController)
viewController.takenImage = imageToTransmit
}
}
The Image is being sent, but the Segue does not perform.Please help!
UPDATE
I went with the idea to send the image as sender, without saving in current ViewController and it worked like a charm!
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info:[String : Any]) {
let tempImage: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.dismiss(animated: true) {
self.performSegue(withIdentifier: "cameraSegueIdent", sender: tempImage)
}
}
Following might helpful.
let tempImage: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
let imagetoTransmit: UIImage = tempImage
shootedImage = imagetoTransmit
_ picker.dismissViewControllerAnimated(true, completion: {
self.performSegue(withIdentifier: "cameraSegueIdent", sender: nil)
})
Also, make sure that the segue identifier is correctly configured in your storyboard.

Resources