I've tried exhaustively to find the answer to this problem. In the app that I am creating the user will click addImage button and then select an image from the photo library (or camera) from ImagePickerController and then that selected image gets passed to an image view on a second view controller.
I know how to do this when the image view is on the same view as the addImage button but can't figure out how to properly use a segue to pass the image to the second view. Hopefully, someone can help me sort this out.
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
var newImage = UIImage(named: "")
#IBOutlet var imageView: UIImageView!
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addImage(sender: UIButton) {
var alert = UIAlertController(title: "Please Get An Image", message: "Choose from below", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Camera", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Photo Library", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: {(action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
newImage = image
//not sure about this next line here...
performSegueWithIdentifier("VC2", sender: self)
self.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var secondViewController: VC2 = segue.destinationViewController as! VC2
secondViewController.imageView.image = newImage
}
}// end of app
you should not pass the UIImage by using the UIImageView object because this is not a Good idea to pass the image like this, Instead you can create UIImage object in SecondViewController simple pass the UIImage object to that and in SecondVC use this image object like this
override func viewDidLoad() {
super.viewDidLoad()
if imageView != nil {
imageView.image = newImage
}
}
OK susan, so when you click "Use Photo" in the preview part of the camera, that's where you want to implement to segue to the second VC.
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
newImage = image
dismissViewControllerAnimated(true, completion: { () -> Void in
//Will call segue name
self.performSegueWithIdentifier("Your_Segue_name", sender: self)
})
}
EDIT: The above code will segue after you've confirmed that you want to use the image.
In your second VC, have a holder to hold then sent that holder image to your UIImageView. In your 1st VC, sent the image to transfer to the holder image.
Your SecondVC:
#IBOutlet var imgView: UIImageView!
var holderImage: UIImage?
In your viewDidLoad()
imgView.image = holderImage.image
Make sure the segue has its identifier set as "VC2". Also, instead of setting
secondViewController.imageView.image = newImage
expose a property on your secondViewController that takes the image. Set the property with the image in prepareForSegue.
secondViewController.image = newImage
Then, in viewDidLoad on secondViewController set its imageView with the value from the property.
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = image
}
In your code the ImageView on the second controller doesn't exist yet because of the view life cycle.
You can also set a breakpoint in prepareForSegue to make sure it's being called properly and the second controller is being set properly.
Related
I have a button within tableViewcell with Image contained in it. I want to get option to change the image on tapping the previous image(which is a button),like opening gallery or camera.I am using following code to implement this:
In tableView cell:
protocol Profile2 : class{
func OnClick_2(index : Int)
}
class TableViewCell: UITableViewCell {
weak var celldelegate : Profile2?
var index : IndexPath?
}
In View Controller
#IBAction func changeProfileImage(_ sender: Any) {
let action_sheet = UIAlertController(title: "Click to choose photo", message: nil, preferredStyle: .actionSheet)
action_sheet.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { (action) in
self.ShowAlbum()
}))
action_sheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
}
//Show album method
func ShowAlbum()
{
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
imagePicker.allowsEditing = true
}
//In cell for row method:
cell.celldelegate = self
cell.index = indexPath
cell.profilePicture.isUserInteractionEnabled = true
//imagepicker method
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!){
self.dismiss(animated: true, completion: { () -> Void in
})
let cell = tableView.dequeueReusableCell(withIdentifier: "profilePictureCell") as! TableViewCell
cell.profilePicture.imageView?.image = image
}
on tapping the button actionsheet is opened for uploading image from gallery but on selecting image and uploading it is not getting set into the button.
Please suggest me how to solve it or do it in alternative way.
I'm trying to use a UIImagePickerController to show a image picked from the Photo Library, but when I select the image, nothing happens.
All I'm doing is from Apple's Swift tutorial, so the code shouldn't be wrong, I guess. It doesn't work neither in simulator nor on a real device. I've tried all suggestions I found while googling. My code:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//MARK: Properties
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var mealNameLabel: UILabel!
#IBOutlet weak var photoImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
nameTextField.delegate = self
}
//MARK: Actions
#IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
// Hide the keyboard.
nameTextField.resignFirstResponder()
// UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked, not taken.
imagePickerController.sourceType = .photoLibrary
// Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// Dismiss the picker if the user canceled.
dismiss(animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
}
#IBAction func setDefaultLabelText(sender: UIButton) {
mealNameLabel.text = "Default Text"
}
//MARK: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
mealNameLabel.text = textField.text
}
}
I can provide more information if necessary. Thanks in advance.
Your delegate method is in the button action scope.
You have to write UIImagePickerControllerDelegate method out of the selectImageFromPhotoLibrary action scope and write with the proper signature.
Just like that:
#IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
// Hide the keyboard.
nameTextField.resignFirstResponder()
// UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked, not taken.
imagePickerController.sourceType = .photoLibrary
// Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// Dismiss the picker if the user canceled.
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
In my FirstVC I understand how to work with the UIImagePickerController, load the camera, take a photo, display it inside 1 imageView (still within the FirstVC) and then pass that image to an imageView inside the SecondVC via prepareForSegue to be shown over there.
What I need help with is having multiple imageViews inside FirstVC so that once a user takes the first picture it loads into the 1st imageView, then second picture the 2nd imageView, 3 pic to 3rd imageView, and 4th pic to 4th imageView. Afterwards an alert would appear that would say the user can't take any more pics and the user would press a nextSceneButton to be taken be taken to the SecondVC which would display the 4 chosen images that they just took.
I always used UIImagePickerController but I just got acquainted with AVFoundation. Should I use AVFoundation or UIImagePicker for this task?
Here is my UIImagePickerController code with only one imageView inside the FirstVC:
import UIKit
class FirstViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var nextSceneButton: UIButton!
//nextSceneButton is connected in StoryBoards and triggers the segue to the SecondVC
let imagePicker = UIImagePickerController()
var image: UIImage?
//MARK:- Custom Function
func noCamera(){
let alertVC = UIAlertController(title: "No Camera", message: "Sorry, this device has no camera", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style:.Default, handler: nil)
alertVC.addAction(okAction)
presentViewController(alertVC, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK:- Buttons
#IBAction func libraryButtonPressed(sender: UIButton) {
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBAction func photoButtonPressed(sender: UIButton) {
if (UIImagePickerController.availableCaptureModesForCameraDevice(UIImagePickerControllerCameraDevice.Rear) != nil){
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Photo
imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.Rear
presentViewController(imagePicker, animated: true, completion: nil)
}else{
noCamera()
}
}
//MARK:- ImagePickerController Delegates
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.image = chosenImage
imageView.image = self.image
dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.dismissViewControllerAnimated(true, completion: nil)
}
//MARK:- Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == “fromPhotoVcToSecondVC” {
let secondVC = segue.destinationViewController as! SecondViewController
secondVC.image = self.image
}
}
}//end class
You can add a count property and hold your images in an array :
var count = 0
var imageViews:[UIImageView]
Every time you take a photo and delegate gets called load the respective imageview :
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.imageViews[count].image = chosenImage
count +=1
dismissViewControllerAnimated(true, completion: nil)
}
Then if all photos are taken alert the user :
#IBAction func photoButtonPressed(sender: UIButton) {
if count < imageViews.count {
//present UiimagePicker
} else {
// alert no more pictures allowed
}
}
I've 2 VC :
The first VC with 1 button when tapped >> 2 options post image form cam or library
Second VC chosen image form VC1 segued to the second VC
I tried to figured This the error without any success
fatal error: unexpectedly found nil while unwrapping an Optional value
pointed at
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
I uploaded the project in dropbox https://www.dropbox.com/s/w7blbnyac9qyxgw/segImage.zip?dl=0
VC1
class ViewController:UIViewController,UIAlertViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIPopoverControllerDelegate
{
#IBOutlet weak var btnClickMe: UIButton!
#IBOutlet weak var imageView: UIImageView!
var picker:UIImagePickerController?=UIImagePickerController()
var popover:UIPopoverController?=nil
override func viewDidLoad()
{
super.viewDidLoad()
picker!.delegate=self
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "" ) {
let destVC : second = segue.destinationViewController as! second
destVC.pics = imageView.image!
}
}
#IBAction func btnImagePickerClicked(sender: AnyObject)
{
let alert:UIAlertController=UIAlertController(title: "Choose Image", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default)
{
UIAlertAction in
self.openCamera()
}
let gallaryAction = UIAlertAction(title: "Gallary", style: UIAlertActionStyle.Default)
{
UIAlertAction in
self.openGallary()
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel)
{
UIAlertAction in
}
// Add the actions
picker?.delegate = self
alert.addAction(cameraAction)
alert.addAction(gallaryAction)
alert.addAction(cancelAction)
// Present the controller
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(alert, animated: true, completion: nil)
}
else
{
popover=UIPopoverController(contentViewController: alert)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
}
func openCamera()
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
{
picker!.sourceType = UIImagePickerControllerSourceType.Camera
self .presentViewController(picker!, animated: true, completion: nil)
}
else
{
openGallary()
}
}
func openGallary()
{
picker!.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
{
self.presentViewController(picker!, animated: true, completion: nil)
}
else
{
popover=UIPopoverController(contentViewController: picker!)
popover!.presentPopoverFromRect(btnClickMe.frame, inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
picker .dismissViewControllerAnimated(true, completion: nil)
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker: UIImagePickerController)
{
print("picker cancel.")
}
}
second VC
class second: UIViewController {
var pics = UIImage()
#IBOutlet var image: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if let img = UIImage(named: "pics")
{
self.image.image = img
}
}
Your storyboard wiring is wrong.
The image should really be set on an instance of second rather than an instance of ViewController. Notice that the crash is happening in ViewController and not second
This code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
picker .dismissViewControllerAnimated(true, completion: nil)
imageView.image=info[UIImagePickerControllerOriginalImage] as? UIImage
}
is attempting to set an imageView.image in ViewController. If you look at the Storyboard, there is no UIImageView in ViewController.
The way that you've defined imageView on ViewController is what makes this crash:
#IBOutlet weak var imageView: UIImageView!
With the ! there, you are saying, "This will never be nil." Well, that's obviously not the case because since this IBOutlet isn't wired to a UIImageView then it is nil. And thus, when you try to access it, BOOM!
To fix this:
Segue to second when the user picks an image
Set the selected image on second's image.imageView property
Other suggestion:
- Use consistency in naming, eg second vs SecondViewController
I've looked all over for a solution but haven't been able to find one. I want to be able to select an Image from the UIImagePicker and have that image go to an ImageView in a Second View Controller. I have a button that triggers an AlertView with options to get photos from camera or library. It works fine if I want the selected image to go to an image view on the first view but I can't get it to work to have it go to a second view. Any suggestions would be greatfully appreciated. `
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
var newImage = UIImage(named: "")
#IBAction func libraryBtn(sender: AnyObject) {
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBOutlet var imageView: UIImageView!
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(named: "beach.jpg" )
imagePicker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addButton(sender: UIButton) {
var alert = UIAlertController(title: "Please Get An Image", message: "Choose from below", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Camera", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Photo Library", style: .Default, handler: {(action) -> Void in
self.imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(self.imagePicker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: {(action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
newImage = image
performSegueWithIdentifier("VC2", sender: self)
self.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var secondViewController: VC2 = segue.destinationViewController as! VC2
secondViewController.imageView.image = newImage
}
}
I dont know Swift but I do know ObjC, so I will try to explain:
Class 2 .h :
#property (nonatomic, strong) UIImageView *myImageViewer;
Class 1 .m :
mySecondViewController.myImageViewer = [UIImageView new];
[mySecondViewController.myImageViewer setImage: newImage];
First you need to make the ImageView global to be able to access from other controllers. Then after you picked the newImage, you initialize memory to myImageViewer and give it the newImage you just picked, then load the viewController.
Hope this is what you needed to hear?