In iOS Swift 3.1 I'm trying to access the camera, the same way I have done successfully in other apps. However, in this one particular app, it always crashes on the self.present(imagePicker, animated: true, completion: nil) line. The message in the console is Message from debugger: Terminated due to signal 9. Does this usually signal a memory related error?
#IBAction func onChooseImageClick(_ sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.savedPhotosAlbum){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
//Create the AlertController and add Its action like button in Actionsheet
let actionSheetControllerForImage: UIAlertController = UIAlertController(title: "Please select", message: "Option to select", preferredStyle: .actionSheet)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
print("Cancel")
}
actionSheetControllerForImage.addAction(cancelActionButton)
let cameraActionButton: UIAlertAction = UIAlertAction(title: "Camera", style: .default)
{ action -> Void in
print("Camera")
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)) {
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
let mediaTypes:[String] = [kUTTypeImage as String]
imagePicker.mediaTypes = mediaTypes
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
} else {
let alertController = UIAlertController(title: "error", message: "Camera not found!", preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .cancel) { action in
// ...
}
alertController.addAction(OKAction)
self.present(alertController, animated: true)
}
}
actionSheetControllerForImage.addAction(cameraActionButton)
let galleryActionButton: UIAlertAction = UIAlertAction(title: "Image Gallery", style: .default)
{ action -> Void in
imagePicker.sourceType = UIImagePickerControllerSourceType.savedPhotosAlbum;
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
actionSheetControllerForImage.popoverPresentationController?.sourceView = self.view
actionSheetControllerForImage.addAction(galleryActionButton)
===> self.present(actionSheetControllerForImage, animated: true, completion: nil)
}
}
You need a string in your plist file that explains why your app need permission to use the camera. There's a great summary of these strings in the question at iOS 10 - Changes in asking permissions of Camera, microphone and Photo Library causing application to crash, with a list you can copy from in the answer at https://stackoverflow.com/a/40734360/968577
Without the required strings, your app will crash in this manner. However, the console output will explain what the problem is.
Try like this i hope it would be helpful!!
Add these two points in info.plist first
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description
Add these two delegates in your class file
UIImagePickerControllerDelegate
UINavigationControllerDelegate
#IBAction func onclickImageAction(_ sender: Any){
print("onclickImageAction method called here")
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.isEditing = false
let actionSheet = UIAlertController(title: "Select Profile Photo", message: "", preferredStyle: UIAlertControllerStyle.actionSheet)
let libButton = UIAlertAction(title: "Select photo from library", style: UIAlertActionStyle.default){ (libSelected) in
print("library selected")
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
actionSheet.addAction(libButton)
let cameraButton = UIAlertAction(title: "Take a picture", style: UIAlertActionStyle.default) { (camSelected) in
if (UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera))
{
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
self.present(imagePicker, animated: true, completion: nil)
}
else
{
actionSheet.dismiss(animated: false, completion: nil)
let alert = UIAlertController(title: "Error", message: "There is no camera available", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (alertAction) in
alert.dismiss(animated: true, completion: nil)
}))
}
}
actionSheet.addAction(cameraButton)
let cancelButton = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) { (cancelSelected) in
print("cancel selected")
}
actionSheet.addAction(cancelButton)
let albumButton = UIAlertAction(title: "Saved Album", style: UIAlertActionStyle.default) { (albumSelected) in
print("Album selected")
imagePicker.sourceType = UIImagePickerControllerSourceType.savedPhotosAlbum
self.present(imagePicker, animated: true, completion: nil)
}
actionSheet.addAction(albumButton)
self.present(actionSheet, animated: true, completion:nil)
}
Implement these delegate method
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{if let PickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
{
yourimageview.image = PickedImage
dismiss(animated: true, completion: nil)
}
}
I just added exit(0) when i opened the camera settings. It's working fine
Related
I am using Swift 5 code and in code I have to capture image. My source type would be .camera or .photoLibrary. I have perfectly set everything even the permission settings in Info.plist but for unseen reason photo library is not accessible for selecting image. Only camera option is available every time. Please suggest and look into my code what am I doing wrong?
Permission Info.plist:
Privacy - Photo Library Additions Usage Description
Privacy - Photo Library Usage Description
Privacy - Media Library Usage Description
Privacy - Camera Usage Description
Code:
var imagePicker: UIImagePickerController!
enum ImageSource {
case photoLibrary
case camera
}
//MARK: - Take image
func takePhoto() {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
selectImageFrom(.photoLibrary)
return
}
selectImageFrom(.camera)
}
func selectImageFrom(_ source: ImageSource){
imagePicker = UIImagePickerController()
imagePicker.delegate = self
switch source {
case .camera:
imagePicker.sourceType = .camera
case .photoLibrary:
imagePicker.sourceType = .photoLibrary
}
present(imagePicker, animated: true, completion: nil)
}
You always prioritize camera in your guard
//MARK: - Take image
func takePhotoLib() {
guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
return
}
selectImageFrom(.photoLibrary)
}
//MARK: - Take image
func takePhotoCamera() {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
return
}
selectImageFrom(.camera)
}
func selectimage(_ sender: UIButton)
{
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: { _ in
self.openCamera()
}))
alert.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { _ in
self.openGallary()
}))
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
//If you want work actionsheet on ipad then you have to use popoverPresentationController to present the actionsheet, otherwise app will crash in iPad
switch UIDevice.current.userInterfaceIdiom {
case .pad:
alert.popoverPresentationController?.sourceView = sender
alert.popoverPresentationController?.sourceRect = sender.bounds
alert.popoverPresentationController?.permittedArrowDirections = .up
default:
break
}
self.present(alert, animated: true, completion: nil)
}
//MARK: - Open the camera
func openCamera(){
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)){
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
//If you dont want to edit the photo then you can set allowsEditing to false
// imagePicker.allowsEditing = true
imagePicker.delegate = self
imagePicker.modalPresentationStyle = .overCurrentContext
self.present(imagePicker, animated: true, completion: nil)
}
else{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func openGallary(){
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary)){
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.tabBarController?.tabBar.isHidden = true
//If you dont want to edit the photo then you can set allowsEditing to false
// imagePicker.allowsEditing = true
imagePicker.delegate = self
imagePicker.modalPresentationStyle = .overCurrentContext
self.present(imagePicker, animated: true, completion: nil)
}
I think this function is shorter and reduces the extra code.
func selectImageFrom(_ source: UIImagePickerController.SourceType) {
guard UIImagePickerController.isSourceTypeAvailable(source) else {
return
}
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = source
present(imagePicker, animated: true, completion: nil)
}
Change the argument type from ImageSource to UIImagePickerController.SourceType
func selectImageFrom(_ source: UIImagePickerController.SourceType){
imagePicker = UIImagePickerController()
imagePicker.delegate = self
switch source {
case .camera:
imagePicker.sourceType = .camera
case .photoLibrary:
imagePicker.sourceType = .photoLibrary
}
present(imagePicker, animated: true, completion: nil)
}
It should work now.
Sorry, you seem to check whether the device have a camera and then proceed to select that. Show an action sheet for the user to select one of them. It would work.
use this function:
func showOptions(sender: AnyObject) {
let alertController = UIAlertController.init(title: "Choose Option", message: "", preferredStyle: .actionSheet)
let cameraAction = UIAlertAction.init(title: "Camera", style: .default) { (action) in
self.selectImageFrom(.camera)
}
alertController.addAction(cameraAction)
let photoLibraryAction = UIAlertAction.init(title: "Photo Library", style: .default) { (action) in
self.selectImageFrom(.photoLibrary)
}
alertController.addAction(photoLibraryAction)
let cancelAction = UIAlertAction.init(title: "Cancel", style: .cancel) { (action) in
}
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
I'm trying to access both the camera and photo library in swift4 using the following code
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .camera
print(1)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
but it's not working. I'm not get an access authorization request even though I made sure that the plist has the camera and photo library authorization. I manipulate the code a bit to the following
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
}
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .notDetermined {
PHPhotoLibrary.requestAuthorization({status in
})
}
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .camera
print(1)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
Now I am getting the authorization request for both cameras and photo library and I can see the AlertView but when I press camera or Photo Album as shown in the picture nothing happens.
I tried on a device and simulator for the camera.
Here is the code to load image from photos & camera in iOS.
⁃ You need to create an outlet of your UIImageView
⁃ Then add a tap gesture on to image view
⁃ Then connect tap gesture with the didTapOnImageView function.
⁃ Then add the following extension to your view controller.
//MARK:- Image Picker
extension YourViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//This is the tap gesture added on my UIImageView.
#IBAction func didTapOnImageView(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?.profileImgView.image = image
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
Note: Don't forget to add the privacy settings in info.plist
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description
First of all, you need to import these libraries:
import Photos
import UIKit
#IBOutlet weak var loadPhoto: UIButton!
And you need setup delegates:
class YourClass: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UNUserNotificationCenterDelegate
func displayUploadImageDialog(btnSelected: UIButton) {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
let alertController = UIAlertController(title: "", message: "Upload profile photo?".localized(), preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel action"), style: .cancel, handler: {(_ action: UIAlertAction) -> Void in
alertController.dismiss(animated: true) {() -> Void in }
})
alertController.addAction(cancelAction)
let cameraRollAction = UIAlertAction(title: NSLocalizedString("Open library".localized(), comment: "Open library action"), style: .default, handler: {(_ action: UIAlertAction) -> Void in
if UI_USER_INTERFACE_IDIOM() == .pad {
OperationQueue.main.addOperation({() -> Void in
picker.sourceType = .photoLibrary
self.present(picker, animated: true) {() -> Void in }
})
}
else {
picker.sourceType = .photoLibrary
self.present(picker, animated: true) {() -> Void in }
}
})
alertController.addAction(cameraRollAction)
alertController.view.tintColor = .black
present(alertController, animated: true) {() -> Void in }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
profileImage.image = image
let imageData = UIImageJPEGRepresentation(image, 0.05)
self.dismiss(animated: true, completion: nil)
}
func checkPermission() {
let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
switch authStatus {
case .authorized:
self.displayUploadImageDialog(btnSelected: self.loadPhoto)
case .denied:
print("Error")
default:
break
}
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}
func checkLibrary() {
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .authorized {
switch photos {
case .authorized:
self.displayUploadImageDialog(btnSelected: self.loadPhoto)
case .denied:
print("Error")
default:
break
}
}
}
Setup action for button:
#IBAction func loadPhotoTapped(_ sender: UIButton) {
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .notDetermined {
PHPhotoLibrary.requestAuthorization({status in
if status == .authorized{
print("OKAY")
} else {
print("NOTOKAY")
}
})
}
checkLibrary()
checkPermission()
}
At the Info.plist setup the permissions:
Privacy - Media Library Usage Description
Privacy - Photo Library Usage Description
Privacy - Camera Usage Description
This should work.
Im working in an application which requires the camera. The way Im opening it is this:
let Picker = UIImagePickerController()
Picker.delegate = self
Picker.sourceType = .camera
present(Picker, animated: true, completion: nil)
Everything works perfectly, this is the result which I get:
What I would like to do now is replace that "Cancel" button for a button which let the user select a photo from his photolibrary. I have been reading a lot but I still do not get a solution.
Thank to everyone
You can do it instead of that
#IBAction func buttonOnClick(_ sender: UIButton)
{
let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { _ in
self.openCamera()
}))
alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in
self.openGallary()
}))
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
/*If you want work actionsheet on ipad
then you have to use popoverPresentationController to present the actionsheet,
otherwise app will crash on iPad */
switch UIDevice.current.userInterfaceIdiom {
case .pad:
alert.popoverPresentationController?.sourceView = sender
alert.popoverPresentationController?.sourceRect = sender.bounds
alert.popoverPresentationController?.permittedArrowDirections = .up
default:
break
}
self.present(alert, animated: true, completion: nil)
}
func openCamera()
{
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera))
{
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
else
{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func openGallary()
{
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
Make sure you are doing this 2 things:
Specifying the content type you are looking for:
Picker.mediaTypes = [KUTTypeImage as String, KUTTypeMovie as String], for example to select both videos and images.
That you added in your info.plist the camera permission description Privacy - Camera Usage Description
I have a problem when I want to access to the photo gallery from the user than iOS show first an alert for the permission. I have the same code in one project it show the alert in the other project iOS don't ask me for something there is only a black screen.
The real project...
The test project...
It's really weird because I use the same code...
This is my Swift code :
#IBAction func uploadImagePressed(sender: AnyObject) {
let alertController = UIAlertController(title: "Choose Image", message: "", preferredStyle: UIAlertControllerStyle.ActionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default, handler: { (alertController) -> Void in
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = .Camera
imagePicker.mediaTypes = [kUTTypeImage as String]
imagePicker.modalPresentationStyle = .FullScreen
self.presentViewController(imagePicker, animated: true, completion: nil)
}else{
print("Camera not available on iDevice...")
}
})
let gallery = UIAlertAction(title: "Gallery", style: UIAlertActionStyle.Default, handler: { (alertController) -> Void in
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = .PhotoLibrary
imagePicker.mediaTypes = [kUTTypeImage as String]
imagePicker.modalPresentationStyle = .Popover
self.presentViewController(imagePicker, animated: true, completion: nil)
})
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (alertController) -> Void in})
alertController.addAction(cameraAction)
alertController.addAction(gallery)
alertController.addAction(cancel)
self.presentViewController(alertController, animated: true, completion: nil)
}
there is no error but when i test it on real phone, even in the simulation, it only display a lock image and "This app does not have access to your photos or videos you can enable access in Privacy settings" but when i turn to setting I couldn't find my app in privacy setting. Where did i go wrong?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = false
let selectedSourceAction = UIAlertController(title: "What source do you want to access?", message: "", preferredStyle: UIAlertControllerStyle.ActionSheet)
let fromPhotoLibrary = UIAlertAction(title: "Photo Library", style: UIAlertActionStyle.Default, handler: {(action: UIAlertAction!) -> Void in
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(imagePicker, animated: true, completion: nil)
})
let fromCamera = UIAlertAction(title: "Camera", style: UIAlertActionStyle.Default, handler: {(action: UIAlertAction!) -> Void in
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
self.presentViewController(imagePicker, animated: true, completion: nil)
})
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
selectedSourceAction.addAction(fromPhotoLibrary)
selectedSourceAction.addAction(fromCamera)
selectedSourceAction.addAction(cancelAction)
self.presentViewController(selectedSourceAction, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.clipsToBounds = true
dismissViewControllerAnimated(true, completion: nil)
}
Such bug may happen on IOS 9 when your application's Info.plist file contains a key: "CFBundleDisplayName" with empty string value.