I am attempting to learn more about the delegate pattern. I have written an app that accesses the user's camera roll and I want to display that image on the view controller after the user selects the image. Here is what I have thus far:
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imagePickerView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
// Delegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
imagePickerView.image = image
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func pickAnImage(_ sender: Any) {
let pickerController = UIImagePickerController()
present(pickerController, animated: true, completion: nil)
}
}
The camera roll appears as expected and the Cancel buttons dismiss the modal. Selecting an image also dismisses the modal, however that image is not displayed on the screen. I have confirmed that my imagePickerController is corrected referenced as an outlet. What am I missing?
You have to dismiss the controller once the image is selected, maybe the following detailed function will help you.
For Swift 4.2:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var selectedImageFromPicker: UIImage?
if let editedImage = info[.editedImage] as? UIImage {
selectedImageFromPicker = editedImage
} else if let originalImage = info[.originalImage] as? UIImage {
selectedImageFromPicker = originalImage
}
if let selectedImage = selectedImageFromPicker {
imageView.image = selectedImage
}
dismiss(animated: true, completion: nil)
}
Before Swift 4.2:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicker: UIImage?
if let editedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
selectedImageFromPicker = editedImage
} else if let originalImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
selectedImageFromPicker = originalImage
}
if let selectedImage = selectedImageFromPicker {
imageView.image = selectedImage
}
dismiss(animated: true, completion: nil)
}
Since I've received many points from this answer I'm adding a more concise answer (Just one line is required for setting the image to imageView).
Bonus Answer:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
imageView.image = (info[.editedImage] ?? info[.originalImage]) as? UIImage
dismiss(animated: true)
}
You need to set the view controller as the delegate of pickerController
// pickerController.delegate = self
Also check the imagePickerView outlet is connected.
Ensure you have made all inclusions in the info.plist file
Ensure you have all the delegates set
Ensure what you are using to display image (e.g if editing is set to true, then UIImagePickerControllerEditedImage else UIImagePickerControllerOriginalImage)
Related
I am trying to write a simple app that will update the ImageView with a photo from my photos library. I can open the photos library and select a photo, but after I do that the default image in the ImageViewer does not show up. Any idea why?
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet weak var photoView: UIImageView!
#IBAction func testGesture(_ sender: UITapGestureRecognizer) {
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let selectedImage = info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
photoView.image = selectedImage
dismiss(animated: true, completion: nil)
}
}
You're not using the UIImagePickerControllerDelegate's didFinishPickingMediaWithInfo method. Remove the private and modify the didFinishPickingMediaWithInfo method to the UIImagePickerControllerDelegate method syntax and you're good to go.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
photoView.image = selectedImage
print(selectedImage)
dismiss(animated: true, completion: nil)
}
I'm very new to Xcode and Swift, and I was trying to display an image in a UIImageView that was selected using UIImagePickerController. I linked the UIImageView using an #IBOutlet and I put some if statements at the bottom to allow for editing of the selected picture, but I got stuck when an error popped up in my code. I'm pretty sure that the problem has something to do with how I am referencing the UIImageView, but I don't know how to do it in a different way. I just got this account to ask this question, so forgive me for the way I made this post.
Here is the code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func openPhotosButton(_ sender: UIButton) {
showImagePickerController()
}
#IBOutlet weak var characterView: UIImageView!
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func showImagePickerController() {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.allowsEditing = true
imagePickerController.sourceType = .photoLibrary
present(imagePickerController, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let editedImage = info[UIImagePickerController.InfoKey.editedImage] as UIImage {
characterView.image = editedImage
}
else if let originalImage = info[UIImagePickerController.InfoKey.originalImage] as UIImage {
characterView.image = originalImage
}
dismiss(animated: true)
}
}
Picture from Xcode:
change your method to this one
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let editedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
characterView.image = editedImage
}
else if let originalImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
characterView.image = originalImage
}
dismiss(animated: true)
}
I am trying to select image from camera or gallery and showing the selected image to the screen in my image view. But it's not showing.
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[.originalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
imageview.image = selectedImage
dismiss(animated: true, completion: nil)
}
What am I missing?
In my case the breakpoint function is not at all invoking
If your breakpoint function is not at invoking then I think you have not set the imagePicker delegate in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
I faced same issue before and resolved it by setting image with delay like showed below:
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
self.imageview.image = selectedImage
})
Hope this will help.
Make sure you have UIImagePickerControllerDelegate added to your class and have set your UIImagePickerController instance delegate:
class PickerViewController: UIViewController, UIImagePickerControllerDelegate {
var pickerController = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
pickerController.delegate = self
}
}
Also, it's better to dismiss the picker parameter sent to this delegate:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
...
picker.dismiss(animated: true, completion: nil)
}
I'm using Apple's Swift iOS Tutorial. Which is throwing an error,
Cannot subscript a value of type '[String : Any]' with an index of type 'UIImagePickerController.InfoKey'
The function they defined is below.
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)
}
I'm using Xcode Version 10.0 beta 3, which includes Swift 4.2.
I'd like to understand how to traverse the docs to understand what might have changed or broken.
The signature of the method has changed in Swift 4.2
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])
and you have to write
guard let selectedImage = info[.originalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
You can figure out such terminology changes yourself by reading the documentation or by commenting out the entire method, retype the first few characters and use code completion.
I'm following also the same tutorial, the updated code looks like this:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[.originalImage] 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)
}
Swift 5
In latest version of swift 4 or 5 the delegate method is given below, it should work
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// Code here
}
And use,
guard let selectedImage = info[.editedImage] as? UIImage else {
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[.editedImage] as? UIImage else {
}
}
Use like this,
guard let selectedImage = info[UIImagePickerController.InfoKey.originalImage.rawValue] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
In Swift 4 and 5 like so:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[.editedImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
self.myImageView.image = selectedImage
picker.dismiss(animated: true, completion: nil)
}
I am also following the tutorial. It is working after changing as below.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let selectedImage = info[.originalImage] 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)
}
I am using XCode 11 and Swift 5.
Method has been changed a little bit in Swift 4.2.
First initialise these two variables:
var imagePicker = UIImagePickerController()
var pickedImageProduct = UIImage()
extension yourViewController: UIImagePickerControllerDelegate,UINavigationControllerDelegate{
//create an IBAction to access Camera
#IBAction func accessCameraBtn(_ sender: UIButton) {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerController.SourceType.camera
self.present(imagePicker, animated: true, completion: nil)
}
//create an IBAction to access Gallery
#IBAction func accessGalleryBtn(_ sender: UIButton) {
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
//Final step put this Delegate
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[.originalImage] as? UIImage else {
Print("Error: \(info)")
}
pickedImageProduct = selectedImage
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
In Swift 4.2 you can write the function as:
func photoLib()
{
//opens Photo Library, call the function in a #IBAction func
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType =
UIImagePickerController.SourceType.photoLibrary
myPickerController.allowsEditing = true
present(myPickerController, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let image = info[.editedImage] as? UIImage else {
print("No image found")
photoLabel.text = "Photo Not Found"
return
}
}
I'm making dating app.
as you know, users need to register multiple pictures in dating app.
so i got how to use 1 image picker in one view.
but i don't know how to add multiple image picker.
i know i can only use only one
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
}
and
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
picker.dismissViewControllerAnimated(false, completion:nil)
}
so i cant find solution for multiple imagepicker view.
my failed code is below.
import UIKit
class RegisterPicture : UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBAction func pick1(sender: AnyObject) {
let picker1 = UIImagePickerController()
picker1.sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum
picker1.allowsEditing = true
picker1.delegate = self
self.presentViewController(picker1, animated: false, completion: nil)
}
#IBAction func pick2(sender: AnyObject) {
let picker2 = UIImagePickerController()
picker2.sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum
picker2.allowsEditing = true
picker2.delegate = self
self.presentViewController(picker2, animated: false, completion: nil)
}
#IBOutlet var picture1: UIImageView!
#IBOutlet var picture2: UIImageView!
func imagePickerController(picker1: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
picker1.dismissViewControllerAnimated(false, completion : nil)
self.picture1.image = info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerController(picker2: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
picker2.dismissViewControllerAnimated(false, completion : nil)
self.picture2.image = info[UIImagePickerControllerOriginalImage] as? UIImage
}
func imagePickerControllerDidCancel(picker1: UIImagePickerController) {
picker1.dismissViewControllerAnimated(false, completion:nil)
}
func imagePickerControllerDidCancel(picker2: UIImagePickerController) {
picker2.dismissViewControllerAnimated(false, completion:nil)
}
}
For anyone searching for this in 2020, Apple introduced PHPickerViewController in iOS14. Here's the documentation: https://developer.apple.com/documentation/photokit/phpickerviewcontroller
And the WWDC introduction that explains its usage:
https://developer.apple.com/videos/play/wwdc2020/10652/
You can't select more than one image with UIImagePickerController. You either have to make your own custom image picker that can or use a 3rd party's like this one.
#IBAction func btnTrophy1Action(_ sender: UIButton) {
//GIVE TAG TO YOUR BUTTON
self.view.endEditing(true)
self.senderTag = sender.tag
pickerOpen(sender: sender)
}
#IBAction func btnTrophy2Action(_ sender: UIButton) {
//GIVE TAG TO YOUR BUTTON
self.view.endEditing(true)
self.senderTag = sender.tag
pickerOpen(sender: sender)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
//BASED ON THE TAG SAVE IMAGE TO PARTICULAR IMAGE PICKER
if self.senderTag == 101 {
//TROPHY 1
self.imgTrophy1.image = image
self.isTrophy1Selected = true
} else if self.senderTag == 102 {
//TROPHY 2
self.imgTrophy2.image = image
self.isTrophy2Selected = true
} else {
//TROPHY 3
self.imgTrophy3.image = image
self.isTrophy3Selected = true
}
}
picker.dismiss(animated: true, completion: nil)
}
Here is a solution I tried out to address this sort of problem
I used a single image picker then use an enum holding strings to determine which image view gets the image selected by the user.
enum selectableImage: String {
case image1
case image2
case image3
}
then on each call of the imagePickerController, I assign a variable var imageSelected = selectableImage.image1 like so.
Then finally in the imagePickerController, I used the switched structure like so:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
print("Inside imageController")
print(info)
// The info dictionary may contain multiple representations of the image. You want to use the original.
guard let imagePicked = info[.originalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
// Set photoImageView to display the selected image.
switch imageSelected {
case selectableImage.image1:
image1.image = imagePicked
case selectableImage.image2:
image2.image = imagePicked
case selectableImage.image3:
image3.image = imagePicked
}
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
Hope this helps.
You can't use UIImagePickerController, but you can use a custom image picker. I think ELCImagePickerController is the best option, but here are some other libraries you could use:
Objective-C
ELCImagePickerController
WSAssetPickerController
QBImagePickerController
ZCImagePickerController
CTAssetsPickerController
AGImagePickerController
UzysAssetsPickerController
MWPhotoBrowser
TSAssetsPickerController
CustomImagePicker
InstagramPhotoPicker
GMImagePicker
DLFPhotosPicker
CombinationPickerController
AssetPicker
BSImagePicker
SNImagePicker
DoImagePickerController
grabKit
IQMediaPickerController
HySideScrollingImagePicker
MultiImageSelector
TTImagePicker
SelectImages
ImageSelectAndSave
imagepicker-multi-select
MultiSelectImagePickerController
YangMingShan(Yahoo like image selector)
DBAttachmentPickerController
BRImagePicker
GLAssetGridViewController
CreolePhotoSelection
Swift
LimPicker (Similar to WhatsApp's image picker)
RMImagePicker
DKImagePickerController
BSImagePicker
Fusuma(Instagram like image selector)
YangMingShan(Yahoo like image selector)
NohanaImagePicker
ImagePicker
OpalImagePicker
TLPhotoPicker
AssetsPickerViewController
Alerts-and-pickers/Telegram Picker