So here's my problem. I am trying to create a screen in which there is a UIImageView and a UIButton. When the user presses the button, the camera app opens, you take a photo and if you press "Use Photo" in the Camera app, you are returned to my app's screen and the photo is placed in the UIImageView I mentioned previously.
What happens so far is that when I press the "Use Photo" button, the image is correctly placed in my UIImageView but then the app crashes with the following error:
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryAddUsageDescription key with a string value explaining to the user how the app uses this data.
What I've done so far is:
Placed the key "Privacy - Photo Library Usage Description" with the value "$(PRODUCT_NAME) uses Library in order to process the photos you captured." in the Info.plist file (also checked how it is written in Source form and it's correct according to the Apple Developer Documentation).
Also placed the key "Privacy - Camera Usage Description" with the value "$(PRODUCT_NAME) uses Cameras" in the Info.plist file.
Checked under "TARGETS->->Info->Custom iOS Target Properties" and the 2 key/value pairs that I mentioned in steps 1 and 2, exist.
I will provide you with my code so far:
import UIKit
import Vision
import MobileCoreServices
import AVFoundation
import Photos
class ViewController: UIViewController, UIImagePickerControllerDelegate,
UINavigationControllerDelegate {
var newMedia: Bool?
#IBAction func captureImageButtonPressed(_ sender: Any) {
//let imageName : String = "dolphin"
//randomImageView.image = UIImage.init(named:imageName)
if UIImagePickerController.isSourceTypeAvailable(
UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType =
UIImagePickerControllerSourceType.camera
imagePicker.mediaTypes = [kUTTypeImage as String]
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true,
completion: nil)
newMedia = true
}
}
#IBAction func classifyButtonPressed(_ sender: UIButton) {
performVisionRequest()
}
#IBOutlet weak var randomImageView: UIImageView!
#IBOutlet weak var classificationLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
func performVisionRequest() {
let start = DispatchTime.now()
let model = Resnet50()
let request = VNImageRequestHandler(cgImage: randomImageView.image!.cgImage!, options: [:])
do {
let m = try VNCoreMLModel(for: model.model)
let coreMLRequest = VNCoreMLRequest(model: m) { (request, error) in
guard let observation = request.results?.first as? VNClassificationObservation else { return }
let stop = DispatchTime.now()
let nanoTime = stop.uptimeNanoseconds - start.uptimeNanoseconds
let timeInterval = Double(nanoTime)
self.classificationLabel.text = "\(observation.identifier) (\(observation.confidence * 100)%) in \(timeInterval) seconds."
}
try request.perform([coreMLRequest])
} catch {
print(error)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let mediaType = info[UIImagePickerControllerMediaType] as! NSString
self.dismiss(animated: true, completion: nil)
if mediaType.isEqual(to: kUTTypeImage as String) {
let image = info[UIImagePickerControllerOriginalImage]
as! UIImage
randomImageView.image = image
if (newMedia == true) {
UIImageWriteToSavedPhotosAlbum(image, self,
#selector(ViewController.image(image:didFinishSavingWithError:contextInfo:)), nil)
} else if mediaType.isEqual(to: kUTTypeMovie as String) {
// Code to support video here
}
}
}
#objc func image(image: UIImage, didFinishSavingWithError error: NSErrorPointer, contextInfo:UnsafeRawPointer) {
if error != nil {
let alert = UIAlertController(title: "Save Failed",
message: "Failed to save image",
preferredStyle: UIAlertControllerStyle.alert)
let cancelAction = UIAlertAction(title: "OK",
style: .cancel, handler: nil)
alert.addAction(cancelAction)
self.present(alert, animated: true,
completion: nil)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}
}
Any idea why I get the above error in bold? Thank you very much in advance for your time.
NSPhotoLibraryAddUsageDescription was added in iOS 11.
Please add "Privacy - Photo Library Additions Usage Description" in info.plist with a usage description (string), like you did for the other privacy permissions.
Ref: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html
Related
converted app from swift 3 to swift 4.2.
my app had a upload your profile image feature that is not working anymore and I am trying to figure out why. For now What I see is that
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo
didFinishPickingMediaWithInfo Is not being called after media was chosen
Here is my views full code:
import UIKit
class CameraMenuViewController: BaseViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var UserID:Int = 0
#IBOutlet weak var myImageView: UIImageView!
var callback : ((UIImage) -> ())?
#IBOutlet weak var btn_end: UIButton!
#IBOutlet weak var from_camera: UIBarButtonItem!
#IBOutlet weak var from_gallery: UIBarButtonItem!
#IBAction func btn_end_pressed(_ sender: UIButton) {
//
//self.openViewControllerBasedOnIdentifier("Home")
//let data = UIImagePNGRepresentation(myImageView) as NSData?
let image = myImageView.image!.pngData() as NSData?
//if let data = UIImagePNGRepresentation(myImageView) {
print("callback data")
let userDetails:Dictionary = (UserDefaults.standard.value(forKey: "myUserDetails") as? [String:Any])!
let UserID:Int = userDetails["UserID"] as! Int
print("UserID")
print(UserID)
print("is_selfie from callback")
//save profile image as NewUserID
UserDefaults.standard.set(image, forKey: String(UserID))
UserDefaults.standard.synchronize()
self.view.removeFromSuperview()
//}
}
#IBAction func btn_closer(_ sender: UIButton) {
//self.view.removeFromSuperview()
}
#IBAction func photofromLibrary(_ sender: UIBarButtonItem) {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
picker.modalPresentationStyle = .popover
present(picker, animated: true, completion: nil)
picker.popoverPresentationController?.barButtonItem = sender
}
#IBAction func shootPhoto(_ sender: UIBarButtonItem) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
print("photo shoot")
//UserDefaults.standard.set("selfie", forKey: "is_selfie")
UserDefaults.standard.set(true, forKey: "is_selfie")
UserDefaults.standard.synchronize()
DispatchQueue.main.async {
self.picker.allowsEditing = false
self.picker.sourceType = UIImagePickerController.SourceType.camera
self.picker.cameraCaptureMode = .photo
self.picker.modalPresentationStyle = .fullScreen
self.present(self.picker,animated: true,completion: nil)
}
} else {
noCamera()
}
}
let picker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
picker.delegate = self
DispatchQueue.global(qos: .userInitiated).async
{
self.present(self.picker, animated: true, completion: nil)
}
let language = UserDefaults.standard.object(forKey: "myLanguage") as! String
if(language=="arabic"){
//from_camera.setTitle("كاميرا",for: .normal)
//from_gallery.text.setTitle("الصور",for: .normal)
btn_end.setTitle("إنهاء",for: .normal)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - Delegates
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let chosenImage = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)] as! UIImage //2
myImageView.contentMode = .scaleAspectFit //3
myImageView.image = chosenImage //4
myImageView.layer.borderWidth = 1
myImageView.layer.masksToBounds = false
myImageView.layer.borderColor = UIColor.black.cgColor
myImageView.layer.cornerRadius = myImageView.frame.height/4
myImageView.clipsToBounds = true
callback?(chosenImage)
dismiss(animated:true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
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)
present(
alertVC,
animated: true,
completion: nil)
}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
return input.rawValue
}
Please help me understand why didFinishPickingMediaWithInfo isn't getting called anymore
It appears as though the function declaration changed between Swift 3 and 4.2. This mustn't have been updated for you by the Swift Migrator Tool. One trick I do when this happens, to check what the correct function declaration is, is to use multiline comment syntax to comment out your current function (didFinishPickingMediaWithInfo in your case). Then you can start typing the function out again, and use Xcode autocomplete to ensure you have it correct. You can then copy the contents of the function you commented out to this new and correct function declaration.
Or - you could just look it up the documentation! According to the documentation on imagePickerController, the function should be declared as:
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])
If you replace your function declaration with the above, it should get called again.
As Craig said you need to change delegate function declaration and also afterwards you need to update the following:
let chosenImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
These two changes combined should solve your issue.
i think the name off the function is update
this is my code in My app And work greate
extension FCViewController: UIImagePickerControllerDelegate
{
internal func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])
{
if let photo = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
}
// Any Code Here ...
I'm trying to use Firebase on IOS (Swift) to upload an image file chosen by the user to the firebase storage.
I've already authenticated the user, so that is not the problem.
Below you can see the view controller that I'm trying to use, but when it tries to upload the image, I get back an error message saying:
Object images/vesVLmkqS2cCLQTJOjv9CFe8mh22/0524729A-855E-4E63-8C11-50F4C4B1A905 does not exist.
(you can see in the code that the middle part of this path is the user uid, so I definitely have an authenticated user)
I tried to simplify this path before to test value like "myimage.png" but didn't help, I got the same error.
I've already tried everything I could, please help me because I can't find anything related in the firebase documentation.
The code below automatically opens the image picker when the view loads. If the user chooses an image, we set it to an image view. When the user clicks the upload button, the controller tries to upload the file to firebase storage.
import UIKit
import Firebase
class ShareViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
#IBAction func onPictureTapped(_ sender: Any) {
present(imagePicker, animated: true, completion: nil)
}
#IBAction func onUploadClicked(_ sender: Any) {
if let pickedImage = imageView.image, let imageData = UIImagePNGRepresentation(pickedImage) {
let storageRef = Storage().reference()
let imageRef = storageRef.child("images/\(Auth.auth().currentUser!.uid)/\(NSUUID().uuidString)")
imageRef.putData(imageData, metadata: nil) { (metadata, error) in
if error != nil {
NSLog(error!.localizedDescription)
}
self.navigationController?.popToRootViewController(animated: true)
}
}
}
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageView.contentMode = .scaleAspectFit
imageView.image = pickedImage
}
self.dismiss(animated: true, completion: nil)
}
}
Ok, I found the problem:
// Instead of this:
Storage().reference()
// You need to use this
Storage.storage().reference()
This is ridiculous that there are no warnings about this, also the app don't crash. Very annoying, and it took me at least 5 hours to find
How can I use a picture from the Photo Library in my app? I have done the tutorials about credating a photo app. That all works fine. I have a UIPickerController, can take a picture with the camera, save it to the library, or select an image from the library, which is then put onto the screen. But...
What I want is that the user selects a picture, remember the name of the picture or the number or something, and then on another page use this picture from the library.
Like selecting an avatar. Saving the picture somewhere and whenever the user enters the profile page, open up this avatar picture previously selected. So what I need is the "name"(represenation) of the picture, but I can't find that. How do I do that?
(the code below is just the working cam/lib app part, but it saves the picture without name, that's the problem: How do I find out what picture was saved earlier?) P.S. Sorry, variable names are in Dutch.
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var plaatje: UIImageView!
#IBAction func saveknop(_ sender: UIButton) {
let imageData = UIImageJPEGRepresentation(plaatje.image!, 0.6)
let compressedfoto = UIImage(data: imageData!)
UIImageWriteToSavedPhotosAlbum(compressedfoto!, nil, nil, nil)
saveNotice()
}
#IBAction func cameraknop(_ sender: UIButton) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
}
#IBAction func biepknop(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
plaatje.image = image
self.dismiss(animated: true, completion: nil)
}
func saveNotice() {
let alert = UIAlertController(title: "foto genomen", message: "je foto is bewaard in de biep", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(defaultAction)
present(alert, animated: true, completion: nil)
}
}
One solution I found is to use UIImageJPEGRepresentation or UIImagePNGRepresentation to convert the image into a Data object. From there you can use the write(to:) method to save it to the specific URL you want your app to use.
The answer to this SO question shows a few ways to store the image. It might be of help.
I had the same trouble earlier, this did the trick for me:
Save images using the following method:
func saveImage(image: UIImage, path: String ) {
let pngImageData = UIImagePNGRepresentation(image)
do {
try pngImageData?.write(to: URL(fileURLWithPath: path), options: .atomic)
} catch {
print(error)
}
}
Load saved images using:
func loadImageFromName(name: String) -> UIImage? {
let path = self.fileInDocumentsDirectory(filename: name)
let image = UIImage(contentsOfFile: path)
if image == nil {
print("Image not available at: \(path)")
}
return image
}
func fileInDocumentsDirectory(filename: String) -> String {
let documentsFolderPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as NSString
return documentsFolderPath.appendingPathComponent(filename)
}
Call the save method like this:
saveImage(image: image, path: fileInDocumentsDirectory(filename: "someId"))
Good luck! Hope this helps.
Struggeling with the suggestions, I found another solution, that is strangely simple. But it works! Weird. It is not the best one, but for now I'll use this, untill I understand everyuthiong about the directorys and filesystem on the iphone.
P.S. credit goes to: http://theswiftguy.com/index.php/2016/11/10/how-to-save-an-image-locally-in-xcode-8-swift-3-0/
//Encoding
let image = UIImage(named: "dog.png")
let imageData:NSData = UIImagePNGRepresentation(image!)! as NSData
//Saved image
UserDefaults.standard.set(imageData, forKey: "savedImage")
//Decode
let data = UserDefaults.standard.object(forKey: "savedImage") as! NSData
myImageView.image = UIImage(data: data as Data)
Trying to follow the FoodTracker Apple tutorial. xCode 8.1. I get this crashlog:
2016-11-06 16:49:17.922832 FoodTracker[2307:660318] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.
(lldb)
I have read several posts on missing privacy keys in iOS 10, and so I added the required key...
Privacy - Photo Library Usage Description
...and a custom message under the value column. Yet I still get the same crash when I tap the image. Any help would be great. I would love to finish this tutorial.
Thanks!
INFO:
I cannot include a screenshot of my info.plist yet, so here is the link to a screenshot:
screenshot of info.plist
Here is my ViewController.swift just in case:
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: UITextFieldDelegate
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Hide the keyboard
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
mealNameLabel.text = textField.text
}
// MARK: UIImageControllerDelegate
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: (nil))
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
photoImageView.image = selectedImage
dismiss(animated: true, completion: (nil))
}
// MARK: Actions
#IBAction func selectImageFromPhotoLibrary(_ sender: UITapGestureRecognizer) {
nameTextField.resignFirstResponder()
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
}
#IBAction func setDefaultLabelText(_ sender: UIButton) {
mealNameLabel.text = "Default Text"
}
}
There are a total of 3 Info.plist files under the FoodTracker project. Make sure you're editing the one under the 'FoodTracker' folder. Also, make sure that the property is not cascaded under any existing array property.
You may need to make sure that your app has been granted permission. Though you may have added the info.plist string now, since you have run the app on your device already it may be holding on to the error. I would suggest doing a clean. Delete your derived data "Shortcut" Command + Option + Sift + k and delete the app form the device and build/run again. If that does not solve the problem you should look into if you actually have the ability to use that source.
func pickPhoto() {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
showPhotoMenu()
} else {
choosePhotoFromLibrary()
}
}
Because if you are on a simulator you don't actually have a camera like you do on a real device. This would cause a crash. If that does not solve it you can just check the permissions for that media type.
let status = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
if status == AVAuthorizationStatus.denied {
let changeYourSettingsAlert = UIAlertController(title: "You do not have permissions enabled for this.", message: "Would you like to change them in settings?", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: { (UIAlertAction) -> Void in
guard let url = URL(string: UIApplicationOpenSettingsURLString) else {return}
UIApplication.shared.openURL(url)
})
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
changeYourSettingsAlert.addAction(okAction)
changeYourSettingsAlert.addAction(cancelAction)
presentAlert(sender: changeYourSettingsAlert)
}
The other half is how to give them an option to open Settings for the user.
I hope that helps good luck🖖🏼
I would like to make Facebook share button on my app that shares the image that is loaded from the UIImageview. I cannot figure out how to do it.. There is option to add the text on Facebook share window, but can't add the image. Please help.
import UIKit
import Social
class ViewController: UIViewController {
#IBOutlet weak var saveButtonVar: UIButton!
#IBOutlet weak var image: UIImageView!
#IBAction func facebookBtn(sender: AnyObject) {
var facebookBtn : SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
facebookBtn.setInitialText("I am sharing my motivation with you!")
facebookBtn.addImage(UIImage(named: "motImg")) //????
self.presentViewController(facebookBtn, animated: true, completion: nil)
}
#IBAction func twitterBtn(sender: AnyObject) {
}
#IBAction func saveButton(sender: AnyObject) {
UIImageWriteToSavedPhotosAlbum(image.image, nil, nil, nil)
let alertController = UIAlertController(title: "Image Saved!", message:
"", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
}
#IBAction func button(sender: AnyObject) {
load_image("https://dl.dropboxusercontent.com/u/26347781/Images/Image\(arc4random_uniform(17) + 1).jpg")
saveButtonVar.hidden = false
}
func load_image(urlString:String)
{
var imgURL: NSURL = NSURL(string: urlString)!
let request: NSURLRequest = NSURLRequest(URL: imgURL)
NSURLConnection.sendAsynchronousRequest(
request, queue: NSOperationQueue.mainQueue(),
completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
if error == nil {
self.image.image = UIImage(data: data)
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
saveButtonVar.hidden = true
image.image = UIImage(named: "motImg")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Swift 4
Integrate FacebookShare sdk.
People can share photos from your app to Facebook with the Share Dialog or with a custom interface:
-Photos must be less than 12MB in size.
-People need the native Facebook for iOS app installed, version 7.0 or higher
#IBAction func facebookBtn(sender: AnyObject) {
let shareImage = SharePhoto()
shareImage.image = imageView.image //Image from your imageview
shareImage.isUserGenerated = true
let content = SharePhotoContent()
content.photos = [shareImage]
let sharedDialoge = ShareDialog()
sharedDialoge.shareContent = content
sharedDialoge.fromViewController = self
sharedDialoge.mode = .automatic
if(sharedDialoge.canShow)
{
sharedDialoge.show()
}
else
{
print("Install Facebook client app to share image")
}
}
Hei there!
Check out this guy's answer:
Swift UIActivityViewController Image&Url Share not working with FB
For many people it seemed to work the example in the link, so maybe it does for you, too.
However, so far it did not work for me and I came across your question while still investigating my problem.
As far as adding text, I know this functionality is off for some time, but you should be able to add an url link.
Let me know how this works for you.