iOS - Swift 3 - UIImagePicker avoid "Retake/Use Photo" for multiple photos - ios

I know there are similar questions available on SO.
The reason why I'm starting a new topic.
I want to take multiple photos and save them into an array for later usage (when user finished taking photos)
I already read the API about showsCameraControl, takePicture() and cameraOverlayView
I managed already to capture multiple photos but I have always to confirm every photo with the "Retake/Use Photo" screen. When tipping on Use Photo, the App saves it into the array.
The same way is already working in the Workflow App from DeskConnect. They have a workflow "Take Photo" where you can choose how many photos you want to take. And they are (in my eyes) using Apple's default controls
Any help is appreciated.
Doesn't matter if it's a solution to avoid "Retake/Use Photo" or to create a custom overly view. For me it is important to keep Apple's default controls so the user feels comfortable with the well known controls.
(I also already took a look on the tutorials Apple provides).
My code so far
var imageArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
openCamera()
}
func openCamera() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = false
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageArray.append(pickedImage)
print(imageArray.count)
}
self.dismiss(animated: true, completion: nil)
openCamera()
}

Related

UIImagePickerController Memory Leak Xcode 9 in Swift 4

In my application I found a memory leak when I used the UIImagePickerController, I thought it was my application, but searching for a solution I found an Apple's sample and I also found that this sample has the same memory leak.
You can find the example in the following URL.
https://developer.apple.com/library/content/samplecode/PhotoPicker/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010196
According to the UIImagePickerController documentation:
https://developer.apple.com/documentation/uikit/uiimagepickercontroller
In point 5, thy said that you have to dismiss the image picker using your delegate object, in the Apple's sample the UIImagePickerDelegate is doing the dismiss.
The issue is that the memory leak is wasting approximately 21 MB of memory when you select an image and work with it.
Used Memory without Memory Leak
Used Memory with Memory Leak
Memory Leak
This is the code to present the UIImagePickerController:
#IBAction func showImagePickerForPhotoPicker(_ sender: UIBarButtonItem) {
showImagePicker(sourceType: UIImagePickerControllerSourceType.photoLibrary, button: sender)
}
fileprivate func showImagePicker(sourceType: UIImagePickerControllerSourceType, button: UIBarButtonItem) {
// If the image contains multiple frames, stop animating.
if (imageView?.isAnimating)! {
imageView?.stopAnimating()
}
if capturedImages.count > 0 {
capturedImages.removeAll()
}
imagePickerController.sourceType = sourceType
imagePickerController.modalPresentationStyle =
(sourceType == UIImagePickerControllerSourceType.camera) ?
UIModalPresentationStyle.fullScreen : UIModalPresentationStyle.popover
let presentationController = imagePickerController.popoverPresentationController
presentationController?.barButtonItem = button // Display popover from the UIBarButtonItem as an anchor.
presentationController?.permittedArrowDirections = UIPopoverArrowDirection.any
if sourceType == UIImagePickerControllerSourceType.camera {
// The user wants to use the camera interface. Set up our custom overlay view for the camera.
imagePickerController.showsCameraControls = false
// Apply our overlay view containing the toolar to take pictures in various ways.
overlayView?.frame = (imagePickerController.cameraOverlayView?.frame)!
imagePickerController.cameraOverlayView = overlayView
}
present(imagePickerController, animated: true, completion: {
// Done presenting.
})
}
And this is the code in the delegate to dismiss the UIImagePickerController:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage]
capturedImages.append(image as! UIImage)
if !cameraTimer.isValid {
// Timer is done firing so Finish up until the user stops the timer from taking photos.
finishAndUpdate()
} else {
dismiss(animated: true, completion: nil)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: {
// Done cancel dismiss of image picker.
})
}
fileprivate func finishAndUpdate() {
dismiss(animated: true, completion: { [weak self] in
guard let `self` = self else {
return
}
if `self`.capturedImages.count > 0 {
if self.capturedImages.count == 1 {
// Camera took a single picture.
`self`.imageView?.image = `self`.capturedImages[0]
} else {
// Camera took multiple pictures; use the list of images for animation.
`self`.imageView?.animationImages = `self`.capturedImages
`self`.imageView?.animationDuration = 5 // Show each captured photo for 5 seconds.
`self`.imageView?.animationRepeatCount = 0 // Animate forever (show all photos).
`self`.imageView?.startAnimating()
}
// To be ready to start again, clear the captured images array.
`self`.capturedImages.removeAll()
}
})
}
I'm still looking for a solution, any help will be appreciated.
I had the same issue. So did a ton of other people. Dating back to 2008. Pretty crazy.
http://iphonedevsdk.com/forum/iphone-sdk-development/3816-uiimagepickercontroller-memory-issues.html
UIImagePickerController leaking memory after launch and during taking a picture. Makes app crash after taking more than a 100 pictures
UIImagePickerController Memory Leak
Unfortunately, the best answer I could find was to use a singleton, which sucks. [i.e. Intentionally retain an instance of UIImagePickerController so you just access that every single time you want to select an image.] This is what others have suggested.
Further, I just spent an hour writing this answer with code that uses a singleton, and I just could not avoid a memory leak [although I thought I had for a second]. Maybe I'm just doing it incorrectly - feel free to try. But I won't post my dysfunctional code as an answer.
The best answer [which is how I solved my problem] is to use a third party pod/library. I used ImagePicker, and it is quick, fast, FREE, beautiful, and NO memory leaks! [MIT License]
Check it out here:
https://github.com/hyperoslo/ImagePicker

Capturing gyroscope data at exact moment of photo capture

I'm creating an app that will capture a photo and reorient it based on the gyroscope data at the time of photo capture.
I've created functions to capture the gyro data from the phone in:
startUpdates()
and to stop capturing the data in:
stopUpdates()
I tried adding this into the UIImagePickerController:
if UIImagePickerController.isSourceTypeAvailable(.camera) {
guard ptInitials.text != "" else {
missingIdentifier(text: "Please add an identifier prior to taking a photo")
return}
startUpdates()
imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = false
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.cameraCaptureMode = .photo
imagePicker.modalPresentationStyle = .fullScreen
present(imagePicker,
animated: true,
completion: nil)
}
This starts the gyro capture as the image capture process begins.
I have it passing the gyro data to an optional double, livePhotoAxis: Double?, while it is measuring this inside the "startUpdates()" function.
I was attempting to get it to "stop" capturing the data once the picture is taken so the last known gyro data would be kept in my variable and able to pass into other functions;
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
stopUpdates()
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
saveImageToDocuments(image: chosenImage, fileNameWithExtension: "image.jpg")
dismiss(animated: true, completion: nil
)
}
However, the problem is that the stopUpdates() method isn't called until after the user "confirms" they like their snapped photo (vs retaking it).
From what I've read, there is a private API with uiImagePickerControllerUserDidCaptureItem that captures the exact moment the photo is taken. I could use NSNotification to try and find this and call StopUpdates() once the photo is actually taken.
Is this correct that this is a private API? Can I use that to capture this moment or will my app get rejected?
Likewise, is there a better way to turn off my gyro updates at the exact moment of photo capture?
Thanks!
I added this code and it fixed the problem, but I still don't know if this is a private API and will be allowed in the app store or not? Or if there is a better way to accomplish this?
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object:nil, queue:nil, using: { note in
self.stopUpdates()
})
Update: This doesn't fire the EXACT moment of photo capture. It fires when the photo is "locked in". There are a few seconds (2ish) between the time the take photo button is pressed and the photo locks into place. As a result, if you move the phone during that time, the gyro data will be inaccurate.
Any thoughts on how to improve on this?

cannot Use the "used photo" in IOS swift UIImagePickerController [duplicate]

This question already has answers here:
Swift ImagePickerController didFinishPickingMediaWithInfo not fired
(2 answers)
Closed 6 years ago.
I'm new to swift...
in fact I'm new to Any Apple products. so basically I'm trying to learn how to build and aircraft while trying to fly and learn how to fly it as well. When this disclaimer is out there I'd like some help ;)
My issue is that I cannot get UIImagePickerController to return with an image to me after I've taken one with the Camera. I think I'm missing something fundamental or at least something important to make it work ;)
But I cannot for the life of me figure out where I'm doing it wrong.
this is what I think is the relevant parts of my ViewController however do ask if you feel I'm leaving something important out:
#IBAction func shootPhoto(_ sender: UIButton) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
picker.cameraCaptureMode = .photo
picker.modalPresentationStyle = .fullScreen
present(picker,animated: true,completion: nil)
}
else
{
noCamera()
}
}
private func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let image: UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage;
myImageView.contentMode = .scaleToFill
myImageView.image = image
self.dismiss(animated:true, completion: nil)
}
I must confess I do not know what version of swift I'm using. I'm assuming the latest because I just updated the MacBook Pro until it couldn't do any more. I'm using Xcode 8.2.1 and I'm testing this on a IPhone with IOS 10.2.1 I think it's a IPhone 7s.
Any help is appreciated
Edit:
I'm setting that in this function if that is the wrong place I will move it I just cannot figure out to where. ?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view
picker.delegate = self
}
I'm made aware that this might be a duplicate of another question however when I click to that one they are handling the photo library.
I'm trying to handle the camera and I'm having a issue with returning the image to my imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])...
what they talk about doesn't seem to be working for me and they are using things that I've been told is depricated.
edit 2:
this is how I initialise the picker object as well as how the class is defined
class ViewController: UIViewController,UINavigationControllerDelegate,UIImagePickerControllerDelegate {
let picker = UIImagePickerController()
#IBOutlet weak var myImageView: UIImageView!
private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView.image = image
} else if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
myImageView.image = image
}
myImageView.contentMode = .scaleToFill
self.dismiss(animated:true, completion: nil)
}

Image View image not changing after selecting new from library

First off I want to say that I'm by no means an experienced Swift programmer, so if I am missing anything for someone to help me debug my issue - then I'm sorry about that. Just drop a comment and I'll add whatever is necessary to help you help me.
I'm following Apple's guide on how to develop iOS apps with Swift (as seen here).
But for some reason I'm getting this warning:
Instance method 'imagePickerController(picker:didFinishPickingMediaWithInfo:)' nearly matches optional requirement 'imagePickerController(_:didFinishPickingMediaWithInfo:)' of protocol 'UIImagePickerControllerDelegate'
I've attempted to suppress the issue by both using #nonobjc and setting it to private. The problem is that the new image isn't taking the old image's place. Instead it gives me this error in the output:
[Generic] Creating an image format with an unkown type is an error.
This is the code that concerns my tapGesture and the imagePicking:
// MARK: UIImagePickerControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary contains multiple representations of the image, and this uses the original.
let selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
// Set photoImageView to display the selected image.
photoImageView.image = selectedImage
// Dismiss the picker.
dismiss(animated: true, completion: nil)
}
// MARK: Actions
#IBAction func selectTapGestureFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
// Hide the keyboard
nameTextField.resignFirstResponder()
// UIImagePickerController allows users to pick media from their photo library!
let imagePickerController = UIImagePickerController()
// Only allow photos to be picked, not taken
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
If my question isn't clear enough I need help figuring out why the image in my app isn't changing - even though I've followed the guide. I've already noticed some issues that I assume has to do with Xcode having been updated, but not the guide.
It might be worth mentioning that I have already set the info.plist to allow me to access all the necessary security privileges.
I'm running iOS 10.1 and Xcode 8.1
Found a similar issue that together with #Larme's comment helped me solve it:
Similar issue
The code is correct, Please check and sure that you have connect all the necessary outlets.

UIImagePicker - Do not allow panorama to be picked

Looking for help with an image picker. The picker is functioning properly - however - it allows the user to pick from Panorama photos as well as normal photos on their device.
I want to have the picker only allow the user to choose non panorama pictures.
I looked through the dev document and couldn't find anything about this. Any help appreciated! Here's my code:
#IBAction func selectImage(sender: AnyObject) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType =
UIImagePickerControllerSourceType.PhotoLibrary
imagePicker.mediaTypes = [kUTTypeImage as NSString]
imagePicker.allowsEditing = false
self.clearBtn.hidden = false
self.presentViewController(imagePicker, animated: true,
completion: nil)
}
func imagePickerController(picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
self.dismissViewControllerAnimated(true, completion: nil)
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
self.postImage.contentMode = .ScaleAspectFit
self.postImage.image = image
self.hasPicture = true
}
I know that changing the UIImagePickerControllerSourceType to .PhotoLibrary will only allow picking from the camera roll, but I was hoping to still allow shared photo streams and such that just weren't panoramic.
As Christian posted in a comment - there is no native way for a UIImagePicker to only allow certain types of pictures (excluding panorama).
You have to handle validating the image after it is returned.

Resources