How to choose an image that will remain even after exiting the app - swift

I need help please I have a button .. and UIImage without a picture for the user can choose a picture he wants!
And it's important that the user-selected image stays the same once the user is completely signed out of the app
I want the user to select a picture from the gallery or take a picture and then the picture he chose will be displayed on the profile picture and will not disappear even after exiting the application .. The data will be saved
Can I do this please?
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var imageView: UIImageView!
#IBOutlet var chooseBuuton: UIButton!
var imagePicker = UIImagePickerController()
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!){
self.dismiss(animated: true, completion: { () -> Void in
})
imageView.image = image
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
imageView.contentMode = .scaleAspectFill
dismiss(animated: true, completion: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let controller = UIImagePickerController()
controller.delegate = self
controller.sourceType = .photoLibrary
present(controller, animated: true, completion: nil)
}
}

You need to save image in Application storage like UserDefaults, Document directory or in DB if you are using in Application.
Preferably images are saving to Application document directory, you can use below method to save image:
func saveImage(image : UIImage, imageName: String){
let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectoryPath.appendingPathComponent(imageName)
if let data = UIImageJPEGRepresentation(image, 1.0),
!FileManager.default.fileExists(atPath: fileURL.path) {
do {
try data.write(to: fileURL)
print("Image saved")
} catch {
print("Image save error:", error)
}
}
}
You can get back image via below function:
func getImage(imageName: String) -> UIImage?{
let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectoryPath.appendingPathComponent(imageName)
let image = UIImage(contentsOfFile: fileURL.path)
return image
}
In your UIImagePickerControllerDelegate delegate method call function saveImage with image & imageName to save image in document directory permanently:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// Do your stuff here, then save image to document directory:
saveImage(image:image, imageName: "profile.jpg")
}
To show image on your imageView get image from document directory in your viewDidLoad function:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if let image = getImage(imageName: "profile.jpg"){
imageview.image = image
}
}

Related

Select Video Instead of Image using ImagePickerController - Swift

My situation is that I have a working imagepickercontroller that allows the user to pick an image from their camera roll and display it on an imageview inside the application.
The problem is that I also want to be able to do the same thing with videos, and instead, display the video on an avplayer. I've done some research but couldn't find any good sources.
Can someone show me how to do this? possibly by editing the code below?
Thanks in advance!
This is the code I used for importing and displaying images from cameraroll (all above the viewDidLoad()):
#IBOutlet weak var imageView: UIImageView!
// the image picker controller
var imagePicker = UIImagePickerController()
// this is the button you tap to import your photo
#IBAction func imageViewButtonTapped(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
imagePicker.delegate = self
imagePicker.allowsEditing = true
present(imagePicker, animated: true, completion: nil)
}
}
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)
}
try this:
import AVFoundation
class VideoHelper {
static func startMediaBrowser(delegate: UIViewController & UINavigationControllerDelegate & UIImagePickerControllerDelegate, sourceType: UIImagePickerController.SourceType) {
guard UIImagePickerController.isSourceTypeAvailable(sourceType) else { return }
let mediaUI = UIImagePickerController()
mediaUI.sourceType = sourceType
mediaUI.mediaTypes = [kUTTypeMovie as String]
mediaUI.allowsEditing = true
mediaUI.delegate = delegate
delegate.present(mediaUI, animated: true, completion: nil)
}
}
and you can use this as:
let source = UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) ? UIImagePickerController.SourceType.camera : UIImagePickerController.SourceType.savedPhotosAlbum
VideoHelper.startMediaBrowser(delegate: self, sourceType: source)

Why is my code for saving an image to user defaults only working some of the time? Swift

After selecting an image from camera roll, then placing it into an image view, I need to save it to user defaults.
All the code is working, but not reliably, it works maybe 3 out of 5 times.
I believe the problem is the code that adds the image into the array is not great.
I'm very new to Swift and I have no idea how to clean it up, can anyone help please?
Here is my code
class importImageViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var importImage = UIImage()
let defaults = UserDefaults.standard
#IBOutlet weak var saveScreenButton: UIButton!
#IBOutlet weak var importImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func importButton(_ sender: Any) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerController.SourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
{
//on completion
}
}
// I THINK THE PROBLEM IS IN HERE BUT I CANT SEE IT
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
{
importImageView.image = image
if case importImageView.image = image {
importImage = image
}
}
else
{
}
self.dismiss(animated: true, completion: nil)
}
func saveImage()
{
//encode image to user defaults
let imageData:NSData = importImage.pngData()! as NSData
//save image to user defaults
UserDefaults.standard.set(imageData, forKey: "screenShotImage")
}
#IBAction func saveScreenButton(_ sender: UIButton) {
saveImage()
dismiss(animated: true, completion: nil)
}
}
First of all use Data instead of NSData in saveImage()
func saveImage() {
let imageData = importImage.pngData()
UserDefaults.standard.set(imageData, forKey: "screenShotImage")
}
Now, try fetching the image from UserDefaults in viewDidLoad() and set it as importImageView's image,
override func viewDidLoad() {
super.viewDidLoad()
if let data = defaults.data(forKey: "screenShotImage"), let image = UIImage(data: data) {
importImage = image
importImageView.image = image
}
}
Also, modify the imagePickerController(_: didFinishPickingMediaWithInfo:) definition to,
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
importImageView.image = image
importImage = image
}
self.dismiss(animated: true, completion: nil)
}

How to set a Custom Image as ViewController Background

I have created a button that allows me to set an image from the camera roll as the ViewController background (imageView is the background view), but I need to save it and reload it when ViewController loads.
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var backgroundSelectionView: UIView!
#IBOutlet weak var imageView: UIImageView!
#IBAction func imageButton(_ sender: UIButton) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
imageView.image = image
}
self.dismiss(animated: true, completion: nil)
}
}
I think I should use paths (I read it somewhere but I don't know how to do that since I can't find anything). Could you provide advice on how to save and load a CUSTOM image (not a specific one that you manually select and import in your code, I can already do that?)
Welcome to StackOverflow!
The easiest way to do this would likely be to save the image to disk once you have picked it and restore it when ViewController loads.
To save the image, use FileManager and save to the app's document storage:
/// Saves a background image to disk
/// - Parameter image: The background image to save to disk
/// - Returns: true if successful, false otherwise
func saveBackgroundImage(image: UIImage) -> Bool {
// make sure that the image can be transformed into data (assuming PNG)
guard let data = image.pngData() ?? imageView.image?.pngData() else {
return false
}
// ensure that you can write to the document director
guard let directory = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first else {
return false
}
// write the file
do {
try data.write(to: directory.appendingPathComponent("backgroundImage.png")!)
return true
} catch {
print(error.localizedDescription)
return false
}
}
Now, you need a way to retrieve the file:
/// Retrieves the saved background image
/// - Returns: The background image from disk if it exists, or nil
func getSavedBackgroundImage() -> UIImage? {
if let dir = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first {
return UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent("backgroundImage.png").path)
}
return nil
}
Inside your imagePickerController(picker: didFinishPickingMediaWithInfo:) method, when you set the image on imageView, save the background image by calling self.saveBackgroundImage(image: image). If you are not checking the boolean that is returned from saveBackgroundImage(image:), then call it as follows:
let _ = self.saveBackgroundImage(image: image)
to prevent a "Result unused" warning.
Now, implement your viewDidLoad, which is where you will attempt to load the image:
override func viewDidLoad() {
super.viewDidLoad()
if let backgroundImage = self.getSavedBackgroundImage() {
// set the background image on the `imageView`
self.imageView.image = backgroundImage
}
}
Please set backgroundImage as below,
override func viewDidLoad() {
super.viewDidLoad()
assignbackground()
}
func assignbackground(){
let background = UIImage(named: backgroundImage)
var imageView : UIImageView!
imageView = UIImageView(frame: view.bounds)
imageView.contentMode = UIViewContentMode.ScaleAspectFill
imageView.clipsToBounds = true
imageView.image = background
imageView.center = view.center
view.addSubview(imageView)
self.view.sendSubviewToBack(imageView)
}
Please user remaining code as it is as #Leejay Schmidt's code

Show a view in front of the imagePicker

In my application the user can either open the camera roll to select a picture or open the camera to take directly one by himself.
In both cases, the picture selected/taken will also be saved locally for further reference.
The downside is that the saving operation usually freeze the screen until it is finished.
I found an animation in this post and I want to display it in front of the imagePickerController but I can't manage to do so.
class SinglePageViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate, UINavigationBarDelegate {
var spinner: UIActivityIndicatorView?
lazy var showCameraImagePickerController: UIImagePickerController = {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
imagePicker.allowsEditing = false
return imagePicker
}()
lazy var showPhotoImagePickerController: UIImagePickerController = {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
return imagePicker
}()
#IBOutlet weak var photoButton: UIButton!
#IBAction func onPhotoButton(_ sender: Any) {
self.present(self.showCameraImagePickerController, animated: true, completion: nil)
}
#IBOutlet weak var galleryButton: UIButton!
#IBAction func onGalleryButton(_ sender: Any) {
self.present(self.showPhotoImagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
//start animation
let screenSize: CGRect = UIScreen.main.bounds
spinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width / 2 - 150, y: screenSize.height / 2 - 150, width: 300, height: 300))
spinner?.isHidden = false
spinner?.startAnimating()
spinner?.color = UIColor.red
switch picker {
case showCameraImagePickerController:
// snap pic, save to doc, save to album
self.showCameraImagePickerController.view.addSubview(spinner!)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false, block: { _ in
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
if self.saveImage(imageName: "\(self.titleLabel.text!).png", image: image) {
// additionally save to photo album
UIImageWriteToSavedPhotosAlbum(image!, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
print("saved \(self.titleLabel.text!).png")
self.imageView.image = image
}
})
case showPhotoImagePickerController:
//switch pic, save to doc. no album
self.showPhotoImagePickerController.view.addSubview(spinner!)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false, block: { _ in
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
if self.saveImage(imageName: "\(self.titleLabel.text!).png", image: image) {
print("saved new \(self.titleLabel.text!).png")
self.imageView.image = image
self.spinner?.stopAnimating()
self.spinner?.removeFromSuperview()
self.spinner = nil
self.showPhotoImagePickerController.dismiss(animated: true, completion: nil)
} else {
self.spinner?.stopAnimating()
self.spinner?.removeFromSuperview()
self.spinner = nil
self.showPhotoImagePickerController.dismiss(animated: true, completion: nil)
}
})
default:
return
}
}
#objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
spinner?.stopAnimating()
spinner?.removeFromSuperview()
spinner = nil
self.showCameraImagePickerController.dismiss(animated: true, completion: nil)
}
func saveImage(imageName: String, image: UIImage?) -> Bool {
//create an instance of the FileManager
let fileManager = FileManager.default
//get the image path
let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imgDir + imageName)
print(imagePath)
//get the image we took with camera
let image = rotateImage(image: image!)
//get the PNG data for this image
let data = UIImagePNGRepresentation(image)
//store it in the document directory
if fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil) {
newItem?.image = true
return true
} else {
print("error while saving")
return false
}
}
}
as you can see I tried playing with bringSubView(toFront:) and also with the zPosition but with no results.
following this similar question I looked into the documentation for cameraOverlayView but it says that it only works when the imagePicker is presented in camera mode, which doesn't cover the case when I open the photo library
I also recently tried to use a workaround, meaning that I dismiss the imagePickerController as soon as possible and update the image afterwards, but that is not optimal anymore because of some changes in the structure of app.
EDIT
to make myself clearer I'll state again what I need: show the spinner animation in front of the imagePicker, as soon as I tap a photo to choose it, and until I finish saving, then dismiss the imagePicker.
I do not want to first dismiss the picker and then save while showing the spinner in the main view.
EDIT2
updated the code with the new one from the answer. only problem is that if I don't put a timer the spinner shows itself only at the end of the saving process for a brief moment (checked with breakpoints).
This results in no animation during the couple of seconds of saving process and just a brief apparition of the spinner at the end before dismissing the imagePicker.
Just putting a 0.1sec delay triggers the spinner immediately and I get the expected behaviour (animation while saving).
No idea why
Please see a complete example where spinner will show while the image is being saved and once finishes saving spinner will be removed.
class ViewController: UIViewController {
/// Image picker controller
lazy var imagePickerController: UIImagePickerController = {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary;
imagePicker.allowsEditing = false
return imagePicker
}()
var spinner: UIActivityIndicatorView?
#IBAction func imagePickerButton(_ sender: UIButton) {
self.present(self.imagePickerController, animated: true, completion: nil)
}
}
// MARK: ImagePicker Delegate to get the image picked by the user
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//start animation
let screenSize: CGRect = UIScreen.main.bounds
spinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width/2 - 50, y: screenSize.height/2 - 50, width: 100, height: 100))
spinner?.isHidden = false
spinner?.startAnimating()
spinner?.color = UIColor.black
self.imagePickerController.view.addSubview(spinner!)
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
UIImageWriteToSavedPhotosAlbum(image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
#objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
spinner?.stopAnimating()
spinner?.removeFromSuperview()
spinner = nil
self.imagePickerController.dismiss(animated: true, completion: nil)
if error == nil {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}

PhotoPicker discovery error: Error Domain=PlugInKit Code=13

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
I'm trying to display an image from the photo library in a UIImageView
The full error is:
2017-06-09 21:55:59.063307+0200 firstapp2.0[12873:1120778] PhotoPicker
discovery error: Error Domain=PlugInKit Code=13 "query cancelled"
UserInfo={NSLocalizedDescription=query cancelled}
My code is included below:
import UIKit
class ViewController: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate{
#IBOutlet weak var pic: UIImageView!
#IBOutlet weak var text: UILabel!
var chosenImage : UIImage!
override func viewDidLoad() {
super.viewDidLoad()
pic.isUserInteractionEnabled = true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [AnyHashable: Any]) {
var chosenImage = info[UIImagePickerControllerEditedImage]
self.pic!.image = chosenImage as! UIImage
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
#IBAction func tap(_ sender: Any) {
self.text.text = "Kreason"
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
}
You need to make explicit Objective-C reference: #objc
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
image = chosenImage
self.performSegue(withIdentifier: "ShowEditView", sender: self)
dismiss(animated: true, completion: nil)
}
I found this solution. We got this error due to these two reason which is mentioned below.
First we need to call this method in for authorization
Authorization Code
func checkPermission() {
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus() switch photoAuthorizationStatus {
case .authorized: print("Access is granted by user")
case .notDetermined: PHPhotoLibrary.requestAuthorization({
(newStatus) in print("status is \(newStatus)") if newStatus == PHAuthorizationStatus.authorized { / do stuff here */ print("success") }
})
case .restricted: / print("User do not have access to photo album.")
case .denied: / print("User has denied the permission.")
}
}
Correct way of method Calling of didFinishPickingMediaWithInfo
Wrong:
private func imagePickerController( picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
}
Right
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
}
I hope this solution will help you out to resolve this error.
If it works for you don't forget to mark it's as a correct, so this will help to other to find the correct way.
I found it! It is trying to tell you that you do not have authorization to "photos" You need to include the #import <Photos/Photos.h> and request authorization for example like this in Objective-C.
Hope this will save you some time. I spent two full days debugging this!
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusAuthorized:
NSLog(#"PHAuthorizationStatusAuthorized");
break;
case PHAuthorizationStatusDenied:
NSLog(#"PHAuthorizationStatusDenied");
break;
case PHAuthorizationStatusNotDetermined:
NSLog(#"PHAuthorizationStatusNotDetermined");
break;
case PHAuthorizationStatusRestricted:
NSLog(#"PHAuthorizationStatusRestricted");
break;
}
}];
I am sure someone can tell you how to do the same in Swift.
Tried a few of the combination responses without much success.
Using Swift 4, I found that I needed to make sure the following two items were implemented to ensure that the image was selected and placed into the picker (note that the "[discovery] errors encountered while discovering extensions:
Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}"
message still displays in the console, but it does not prevent you from adding an image). Maybe this is a message that results in the picker being dismissed?
1) The delegate for the UIImagePickerController is (UIImagePickerControllerDelegate & UINavigationControllerDelegate)? so need to explicitly add the UINavigationControllerDelegate as one of the protocols:
class ViewController:UIViewController, UIImagePickerControllerDelegate,
UINavigationControllerDelegate { .... }.
2) Make sure that the info.plist has the Privacy - Photo library Usage Description key and String value set.
Of course, you need to ensure that you create a UIImagePickerController and set its delegate equal to self in ViewDidLoad():
class ViewController:UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let imagePickerController = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePickerController.delegate = self
}
...
}
I fixed this issue, call function below into viewdidload or viewWillAppear or viewDidAppear to check permission for your app.
func checkPermission() {
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthorizationStatus {
case .authorized:
print("Access is granted by user")
case .notDetermined:
PHPhotoLibrary.requestAuthorization({
(newStatus) in
print("status is \(newStatus)")
if newStatus == PHAuthorizationStatus.authorized {
/* do stuff here */
print("success")
}
})
print("It is not determined until now")
case .restricted:
// same same
print("User do not have access to photo album.")
case .denied:
// same same
print("User has denied the permission.")
}
}
And to use the above method, do not forget to add import Photos at top of the class.
XCODE 10.1 / SWIFT 4.2 :
Add required permissions (others mentioned)
Implement this delegate func:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.imgView.contentMode = .scaleAspectFit
self.imgView.image = pickedImage
}
dismiss(animated: true, completion: nil)
}
* Missing DELEGATE * in Swift 3
In my case, all settings was correct:
1 - Delegates ( UIImagePickerControllerDelegate,UINavigationControllerDelegate );
2 - Permissions already verified;
3 - Plist already done;
4 - Everything read on this Answers, i did;
But i forgot to implement pickerview.delegate = self on viewDidLoad
Because i COPY and PASTE from my other viewController and forget that!
I hope it help somebody, review your COPY / PASTE first!!!
This might not be the most directly helpful answer - but hopefully it will help! I'm 99% sure that this particular error message isn't actually pointing you to the real problem. I spent hours pulling my hair out over this same exact issue.
1) I had authorization for photos printing to the console when I'd launch my picker, 2) I could navigate and pick a photo easy enough, and 3) when I would return me to my view upon dismissing the picker, my button image wasn't updated with the new photo... and the only hint that I had to the problem was the exact same error message that you are receiving.
Turns out I was hard-coding a placeholder image in ViewWillAppear instead of ViewDidLoad. Every time the picker was dismissing, it was calling ViewWillAppear and replacing my chosen image with my hard coded image. I fixed that issue and sure enough - everything is working fine now... and I'm still seeing that error message every time I return from the picker.
I recommend looking somewhere other than the ImagePicker for your problem and you'll likely find it.
If you have not done so, try this.
Product > Scheme > Edit Scheme > Environment Variables OS_ACTIVITY_MODE: disable
It solves my issue.
I got the same message when I was trying to present another controller from the picker callback imagePickerController. The solution which worked for me was to move my code inside the completion callback from the the picker dismiss method
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
let cropController:CropViewController = CropViewController(croppingStyle: .circular, image: pickedImage)
cropController.delegate = self
self.present(cropController, animated: true, completion: nil)
}
}
}
This fixes the issue in Swift 4:
Change the code below
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {}
to this:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {}
Swift 4.2 update:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){}
Make sure you are subclassing both: UIImagePickerControllerDelegate, UINavigationControllerDelegate.
Also, remember to set the delegate:
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.sourceType = .photoLibrary
picker.delegate = self //Don't forget this line!
self.present(picker, animated: true, completion: nil)
Credits to this source.
Finding the fix for this problem took me forever. It looks like the problem is that the function imagePickerController of the UIImagePickerControllerDelegate cannot be found. If you have set the delegate correctly and it stopped working after upgrading to Swift 4, the problem is probably that you didn't make it accessible to Objective-C by using #objc which is required since Swift 4.
It has to be:
#objc func imagePickerController(...
instead of
func imagePickerController(...
Fixed it by setting 1 second delay when setting image.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
picker.dismiss(animated: false, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
self.discussionImage.image = image
})
}
}
Make sure to add internal func at the beginning and then add the lower case after the parenthesis (_ picker: UIImagePickerController… and then change from AnyObject to Any]…
Check code below:
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
userPhoto.image = pickedImage
}
self.dismiss(animated: true, completion: nil)
}
This had me stumped, but the answer at the link below worked for me. Error is gone and image displays as expected
Like one of the answers above, you have to have (_ picker... but also #objc before the function.
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
...
}
https://forums.developer.apple.com/thread/82105
This solved my error :
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
addPhotoBtn.setImage(pickedImage, for: .normal)
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
Please check by steps as follow:
Import Photos
Has access to album:
func authorizeToAlbum(completion:#escaping (Bool)->Void) {
if PHPhotoLibrary.authorizationStatus() != .authorized {
NSLog("Will request authorization")
PHPhotoLibrary.requestAuthorization({ (status) in
if status == .authorized {
DispatchQueue.main.async(execute: {
completion(true)
})
} else {
DispatchQueue.main.async(execute: {
completion(false)
})
}
})
} else {
DispatchQueue.main.async(execute: {
completion(true)
})
}
}
Present UIImagePickerController
self.authorizeToAlbum { (authorized) in
if authorized == true {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = false
picker.sourceType = .photoLibrary
self.present(picker, animated: true, completion: nil)
}
}
The key step, make sure the delegate method is like following strictly
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
self.pickedImage = pickedImage
if let finalImage = handleImage(originalImage: self.pickedImage!, maskImage: self.maskImage!) {
self.imageView.image = finalImage
}
}
dismiss(animated: true, completion: nil)
}
This is what I did and it solved my issue.
add #objc
add internal
add _ before imagePicker
make sure you are using Any and not AnyObject
Hope this helps!
In my case I was getting this error because I was presenting an image picker controller without first verifying if the user had allowed access to images. Elsewhere in my code the user had granted permission so I think all I needed to do was import Photos. However, since they 'may' not have granted permission at that point in the app adding this just before I presented the image picker controller solved the issue for me (import Photos as well).
// request photos permission if permission has not been granted
if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) in
})
}
If this answer seems redundant my apologies but I had to piece together from a few different answer to get my solution working. Perhaps this will help someone else using Swift 4.
use this code
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])
This "Error Domain=PlugInKit Code=13" error has confounded a lot of people even though it seems to be a harmless apple debug message. I was having trouble getting the image I picked to set in my UI and thought that that error was the problem however it was something a bit more subtle.
I have my image picker controller in a file separate from the view controller that's presenting it.
MyViewController.swift
class MyViewController: UIViewController {
#IBOutlet weak var profileImage: UIImageView!
...
}
extension MyViewController: ImagePickerDelegate {
func didSelect(image: UIImage?) {
self.profileImage.image = image
}
}
ImagePicker.swift
open class ImagePicker: NSObject {
...
private func pickerController(_ controller: UIImagePickerController, didSelect image: UIImage?) {
controller.dismiss(animated: true, completion: {self.delegate?.didSelect(image: image)}
)
}
}
Most of the tutorials and answers have the completion set to nil. However if you set the completion to nil and call the delegate's didSelect method separately, the method gets called but the image doesn't set so make sure to use dismiss' completion.
And again, I know this answer might not be directly related to the original question but I have a feeling a lot of people are coming here for this issue and the given solutions aren't helping. The reason is that most of the people giving answers have their image picker controller in the same class as their main view controller and thus not needing to use a completion.
The Error also happens when you have not configured the permissions of the usage of the Photo Library in you Info.plist file.
You need to add Privacy - Photo Library Usage Description in the Info.plist with a String that will appear when your App tries the first time to access the Photo Library of the User.
The final Info.plist adjustments should look something like this:
I have the same error and I fixed it in this way:
get image object in different way depends on UIImagePickerController allowsEditing is true or false
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if isImagePickerAllowEditing {
sourceImage = info[UIImagePickerControllerEditedImage] as? UIImage
} else {
sourceImage = info[UIImagePickerControllerOriginalImage] as? UIImage
}
....
}
And of course, ask the permission to access photo library first as above comments.
On my end UINavigationControllerDelegate delegate is missing.
class YourViewController:UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate
In my case as swift allocation memory management seems to be optimised and fixed by Apple Team.
My code was perfectly working till a swift update and I found my "mistake" was that I wasn't retaining the picker but It has been working for ages without the retention so here a full ready to work solution.
// Add Privacy - Photo Library Usage Description to your info.plist
<key>NSPhotoLibraryUsageDescription</key>
<string>APPNAME need to access your pictures to violate your privacy :P</string>
And
import Photos
class MyImageSelector: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var picker = UIImagePickerController()
// Make sure to retain this picker var until the picker returned
func checkPermission() {
let call = self.presentAuthorized
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthorizationStatus {
case .authorized:
print("Access is granted by user")
showPicker()
case .notDetermined:
PHPhotoLibrary.requestAuthorization({ newStatus in
print("status is \(newStatus)")
if newStatus == PHAuthorizationStatus.authorized {
/* do stuff here */
print("success")
showPicker()
}
})
case .restricted:
print("User do not have access to photo album.")
case .denied:
print("User has denied the permission.")
}
}
func showPicker() {
picker = UIImagePickerController()
picker.allowsEditing = true
picker.sourceType = .photoLibrary
picker.delegate = self //Don't forget this line!
self.present(picker, animated: true, completion: nil)
}
#objc public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// DO something with picture
}
#objc public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// User cancelled the pick
}
}
I came across the same problem. None of the above mentioned suggestions worked for me. However, I resolved it, by explicilty calling the picker.dismiss and dismiss post that. I am not clear why I have make dismiss calls like that, but it worked for me.
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("Image picked")
picker.dismiss(animated: true, completion: nil)
dismiss(animated: true) {
print("dismissed")
self.delegate?.presentEditor(img: (info[UIImagePickerControllerOriginalImage] as? UIImage)!, id: self.id!)
}
}
I read the all these answers and little bit modified here and not needed to dismiss, this worked for me, Thanks others who have replied here.
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("########### media picked")
picker.dismiss(animated: true, completion: nil)
let img = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
//set img -picked image to "profileImage" UIimageView
//use image here
self.profileImage.image = img
}
}
i found the solution of IMage PickerView.....
#IBOutlet weak var myImageView: UIImageView!
var imagePicker = UIImagePickerController()
#IBAction func selectImage(_ sender: Any) {
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.present(myPickerController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print(info)
var selectedImageFromPicker: UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage
{
selectedImageFromPicker = editedImage as! UIImage
}else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage{
selectedImageFromPicker = originalImage as! UIImage
}
dismiss(animated: true, completion: nil)
if var selectedImage = selectedImageFromPicker
{
myImageView.image = selectedImage
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
click on imageView to load image from photo library and show preview on same imageview. on swift 4
let imagePicker = UIImagePickerController()
#IBOutlet weak var userImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
let tap = UITapGestureRecognizer(target: self, action: #selector(SignUpViewController.click))
userImage.addGestureRecognizer(tap)
userImage.isUserInteractionEnabled = true
}
#objc func click()
{
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let chosenImage = info[UIImagePickerControllerOriginalImage] as? UIImage{
userImage.contentMode = .scaleAspectFit
userImage.image = chosenImage
}
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}