I am working with UIImagePickerController because I am creating an application that allows for the posting of images through both the photo library and camera. I created a basic demo that consists of a UIImageView, UIButton with some code to set up the UIImagePickerController. In addition, I have also set up (NSPhotoLibraryUsageDescription and NSCameraUsageDescription) in the plist section of Xcode. The image picking function works beautifully yet when I run the simulator I am not being queried on whether or not I should let the app allow access to either my camera or photo library. I then tried taking the plist statements off and running again. Without these, the app should crash however it does not. My question is what am I doing wrong here for the picker to work without the plist and why does the app not ask for permissions with the NS usage statements?
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBAction func importImage(_ sender: UIButton) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Add Your Profile Picture", message: "Choose An Option", preferredStyle: . actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}
else {
print("Camera not Available")
}
}))
actionSheet.addAction(UIAlertAction(title: "Camera Roll", style: .default, handler:{ (action:UIAlertAction) in imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil
))
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
imageView.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// 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.
}
}
Storyboard View
plist image
why does the app not ask for permissions with the NS usage statements
This is due to a change in iOS 11. You no longer need user authorization merely to receive a UIImage through the UIImagePickerController.
But if you want deeper information, i.e. access to the image as a PHAsset and its metadata, you do need user authorization.
And of course if you want this app to run on iOS 10 and before, you'll still need user authorization.
Related
I am able to open a Photo Library on an iPhone using the following code:-
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBAction func TapOnImageView(sender: UITapGestureRecognizer) {
//call Alert function
self.showAlert()
}
//Show alert to selected the media source type.
private func showAlert() {
let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .camera)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .photoLibrary)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
}
//get image from source type
private func getImage(fromSourceType sourceType: UIImagePickerController.SourceType) {
//Check is source type available
if UIImagePickerController.isSourceTypeAvailable(sourceType) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = sourceType
self.present(imagePickerController, animated: true, completion: nil)
}
}
//MARK:- UIImagePickerViewDelegate.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.dismiss(animated: true) { [weak self] in
guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
//Setting image to your image view
self?.imageView.image = image
self?.imageView.contentMode = .scaleToFill
self?.image = self?.imageView.image
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
But, when I am running my app on iPad, I am getting the following error:-
Thread 1: Exception: "Your application has presented a UIAlertController (<UIAlertController: 0x7ffd07875e00>) of style UIAlertControllerStyleActionSheet from App Name.ViewController (<App_Name.ViewController: 0x7ffd07635620>). The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation."
Could anyone please let me know, what can I do to open camera and Photo Library on iPad in Xcode? Thanks for the help!
Updated:
Solution:
var alertStyle = UIAlertController.Style.actionSheet
if (UIDevice.current.userInterfaceIdiom == .pad) {
alertStyle = UIAlertController.Style.alert
}
let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: alertStyle)
You are trying to present an UIAlertController on iPad which requires to set modalStyle to UIModalPresentationPopover and its sourceView and sourceRect. Please see this answer for more details.
I have a simple app that allows the user to select an image from their device via Camera Roll or to take a new image. Easy.
I have two buttons;
1) on the navigation bar named Set Image which saves the image to core data
2) on the main view that opens the image picker controller.
My issue;
How do I hide the button on the navigation bar if an image has not been selected?
import UIKit
class CameraRollViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.setBackgroundImage(UIImage(),for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
}
#IBAction func addImage(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Lets customize your Reminders Page", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("Camera not available")
}
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
Anyone have any idea how to do this?
I have multiple buttons on the screen.
When you click a button it calls a function that uses UIImagePickerController to choose an image from either the Library or the Camera and saves that image to the button icon. (so basically clickable pictures).
I am now trying to add some persistence so that when the app is restarted the buttons save their assigned images. I have yet to find an answer I can follow that explains how to achieve this.
I have added the Core Data framework to my project. Can anyone advise on how to proceed. - Thanks.
var newPicImg : UIButton?;
#IBOutlet weak var ButtImg1: UIButton!
#IBOutlet weak var ButtImg2: UIButton!
#IBOutlet weak var ButtImg3: UIButton!
Buttons:
#IBAction func chooseImage(_ sender: UIButton) {
newPicImg = ButtImg1
picStuff()
}
#IBAction func chooseImage1(_ sender: UIButton) {
newPicImg = ButtImg2
picStuff()
}
#IBAction func chooseImage2(_ sender: UIButton) {
newPicImg = ButtImg3
picStuff()
}
Take/Choose Picture:
func picStuff()
{
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action:UIAlertAction)in
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: {(action:UIAlertAction)in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil ))
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
newPicImg?.setImage(image, for: .normal)
picker.dismiss(animated: true, completion: nil)
}
Yes you can use CoreData and create a Database to store the images, then retrieve them. But maybe that is a lot of hassle if you are only going to store 3 images at most, and then maybe change them, but always a maximum of 3.
Maybe a simpler solution would be to save the images to the Documents Directory, with a specific name like imageButton1.png and retrieve them or replace them whenever necessary.
Here a post on how to do it:
Save An Image To Application Documents Folder From UIView On IOS
I need to make a view that works like pages, with a popup in which I can choose to pick a photo from my library or create a new one.
Currently, I have a ViewController, present as Popover. In the ViewController, I inserted a ContainerView and I declared that its class is UIImageViewController. This is showing me the photo library but I don't find how to pick anything in : My ViewController presented as Popover.
When I choose a photo, nothing's happening. I've tried to put some functions
(func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!))
in my ViewController but it does not work. I've read that UIImagePickerController does not support subclassing, so how Pages do this stuff ?
Here is my ViewController code :
import UIKit
class MenuAddResources: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var newMedia: Bool?
let imagePicker = UIImagePickerController()
#IBAction func takePhoto(sender: AnyObject) {
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
//load the camera interface
let picker : UIImagePickerController = UIImagePickerController()
picker.sourceType = UIImagePickerControllerSourceType.Camera
picker.delegate = self
picker.allowsEditing = false
self.presentViewController(picker, animated: true, completion: nil)
self.newMedia = true
}
else{
//no camera available
let alert = UIAlertController(title: NSLocalizedString("ERROR", comment: ""), message: NSLocalizedString("NO_CAMERA", comment: ""), preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .Default, handler: {(alertAction)in
alert.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func image(image: UIImage, didFinishSavingWithError error: NSErrorPointer, contextInfo:UnsafePointer<Void>) {
if error != nil {
let alert = UIAlertController(title: NSLocalizedString("ERROR", comment: ""), message: NSLocalizedString("IMAGE_SAVE_FAILED", comment: ""), preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .Cancel, handler: nil)
alert.addAction(cancelAction)
self.presentViewController(alert, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!){
self.dismissViewControllerAnimated(true, completion: { () -> Void in
})
// Let's store the image
let now:Int = Int(NSDate().timeIntervalSince1970)
let imageData = UIImageJPEGRepresentation(image, 85)
//imageData?.writeToFile(documentsDirectory + "/\(now).jpg", atomically: true)
print(imageData)
/* will do stuff with the image */
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
It appears you are using UIImagePickerViewController through a
container view and therefore the delegate isnt set , thus no callbacks
to receiving the image picked methods.
To fix this, you must override prepareForSegue in your class
and in that cast the segue.destinationViewController to your picker and set its delegate to self
This question already has an answer here:
Thread 1: signal SIGABRT error when using IBActions?
(1 answer)
Closed 7 years ago.
I am writing a basic photo app that allows a user to push a "+" button in a navigation controller and then an ActionSheet pops up from the bottom giving the user options, here is a picture:
I have the code to get this app working using normal buttons, but when I added it to my code for this app it crashes. Here is the code:
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate
{
#IBOutlet weak var imageView: UIImageView!
#IBAction func addPhoto(sender: UIBarButtonItem)
{
let photoOption = UIAlertController(title: nil, message: "Select an Input Type", preferredStyle: .ActionSheet)
let photoLibraryAction = UIAlertAction(title: "Photo Library", style: .Default) { (alert: UIAlertAction!) -> Void in
println("Photo Library Selected") // Used for debugging
// This code worked in my previous app
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .PhotoLibrary
self.presentViewController(picker, animated: true, completion: nil)
}
let cameraAction = UIAlertAction(title: "Camera", style: .Default) { (alert: UIAlertAction!) -> Void in
println("Camera Selected") // Used for debugging
// This code worked in my previous app
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .Camera
self.presentViewController(picker, animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
photoOption.addAction(photoLibraryAction)
photoOption.addAction(cameraAction)
photoOption.addAction(cancelAction)
self.presentViewController(photoOption, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info: [NSObject: AnyObject]!)
{
imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
dismissViewControllerAnimated(true, completion: nil)
}
}
and the strange thing is after I ran this and the app crashed, I reverted back to when the code was working and the app still crashed.
The problem is that you are running this code in the simulator. But the simulator has no camera. It's just a simulator!
Hence, trying to summon an image picker controller with a .Camera source type causes an exception - with a helpful error message in the console that you could have read, thus avoiding wasting bandwidth with this question...