UIImagePickerController extension discovery failed with error: (null) - ios

I'm trying to implement an ImagePicker on my ViewController, but turns out it presents a blank ImagePicker Controller and UIImagePickerController extension discovery failed with error: (null) message on the console.
I have no idea what I'm doing wrong, and I found no information on the matter. One thing I noticed, though, is that the PickerView takes a little bit too long to be presented.
The code related to the ImagePicker is the following:
private let imagePicker = UIImagePickerController()
private func setupImagePicker() {
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
imagePicker.delegate = self
imagePicker.mediaTypes = ["public.image"]
}
#objc private func launchImagePicker() {
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .notDetermined {
PHPhotoLibrary.requestAuthorization({ [weak self] status in
DispatchQueue.main.async {
if status == .authorized, let picker = self?.imagePicker {
self?.present(picker, animated: true, completion: nil)
} else {
self?.present(URealtorUtils.getAlert(message: "You have to authorize photo library access in order to upload a photo"), animated: true, completion: nil)
}
}
})
} else if photos == .authorized {
present(imagePicker, animated: true, completion: nil)
}
}
extension MyController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.viewModel.setPropertyImage(image)
}
dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
This is a screenshot of what I get when the PickerView is presented:

I checked the details, and there are no issues in your implementation.
I also checked the apple's official sample here.
https://developer.apple.com/documentation/uikit/uiimagepickercontroller/customizing_an_image_picker_controller
Same result!
Finally, this is an issue related to iOS Simulators(version 11.3.1).
FYI, I found iPhone 11 Pro Max didn't work in some previous versions, but iPhone 8 and some others worked.
I just want you guys not wasting time on this. Move ahead.
Thanks.

Related

Trying to add UIImagePicker Moving to different ViewController and view is not in heirachy

What I am trying to do
I am trying to present a UIImagePicker to select an image from the phone's photo library
What is the issue
When I run the code I get this error message:
[Presentation] Attempt to present <UIImagePickerController: 0x160062000> on
<Nebula.SettingsViewController: 0x15f51b3c0> (from <Nebula.SettingsViewController:
0x15f51b3c0>) whose view is not in the window hierarchy.
It also navigates to the first View Controller of my app (even if this hasn't been shown before to the user in this session)
What have I tried to do to fix it
I used this post to try and use the topVC and present from there, this stops the error however still returns me to a different View Controller therefore doesn't allow me to run anymore code from the proper view controller
My code
#IBAction func pickTapped(_ sender: Any) {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.delegate = self
picker.allowsEditing = true
//let topVC = topMostController()
//topVC.present(picker, animated: true)
present(picker, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
print("No image selected")
return
}
guard let imageData = image.pngData() else {
print("Something wrong with image data")
return
}
}
top most VC code
func topMostController() -> UIViewController {
var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
return topController
}

How to implement camera functionality in iOS app through XCode

I am starting from zero with iOS app development but I need to create an app that can use the iPhone camera to take an image. I have found UIImagePickerController but I cannot figure out how to implement it correctly. If anyone could help me that would be great. Also I know very little about app development so if there is any background knowledge I would need to understand your answers would be appreciated.
You can call this method wherever you want to open UIImagePickerController:
func openImagePicker() {
let vc = UIImagePickerController()
vc.sourceType = .camera
vc.allowsEditing = true
vc.delegate = self
present(vc, animated: true)
}
Make your view controller conform to both UINavigationControllerDelegate and UIImagePickerControllerDelegate by making an extension like this:
extension youViewControllerClass: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true) // dismisses camera controller
guard let image = info[.editedImage] as? UIImage else {
print("No image found")
return
}
// You will get your image here
print(image.size)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
picker.dismiss(animated: true, completion: nil)
// here you will get the cancel event
}
}

UIImagePickerController not asking for permission

I have implemented the following code in an app to allow the user to add an image to the app. However the user is never asked for permission to access photo's. What am I missing here?
in my info.plist I have set:
Privacy - Photo Library Usage Description = Please provide access to your photo library
The bundle identifier is:
$(PRODUCT_BUNDLE_IDENTIFIER)
import UIKit
class NewPostXIB: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var image: UIImageView!
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
self.view.endEditing(true)
}
#IBAction func closeButton(_ sender: Any) {
dismiss(animated: false, completion: nil)
}
#IBAction func addImageButton(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
imagePicker.allowsEditing = true
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
image.contentMode = .scaleAspectFill
image.image = pickedImage
}
dismiss(animated: false, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
The answer is simple: it's normal behavior since iOS 11, because the UIImagePickerController runs in a separate process and therefore for just read-only access you don't need any special permissions.
According to apple documentation
Note
When using the UIImagePickerController to bring up the user's photo
library, your app doesn't need to request permission explicitly.
Photos automatically prompts the user to request authorization when needed.
Adding the following function solved the problem:
func checkPermission() {
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthorizationStatus {
case .authorized:
present(imagePicker, animated: true, completion: nil)
print("Access is granted by user")
case .notDetermined:
PHPhotoLibrary.requestAuthorization({
(newStatus) in
print("status is \(newStatus)")
if newStatus == PHAuthorizationStatus.authorized {
/* do stuff here */
self.present(self.imagePicker, animated: true, completion: nil)
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.")
}
}

Why doesn't UIImagePickerController delegate to my Object class?

class CameraPicker: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
weak var viewController:MyProfileVC!
func launchCamera() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker:UIImagePickerController = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.front
imagePicker.cameraCaptureMode = .photo
imagePicker.allowsEditing = false
self.viewController.present(imagePicker, animated: true, completion: nil)
} }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("didFinishPickingMedia")
}
This is my object class function, but 'didFinishPickingMediaWithInfo' function doesn't get called after taking the picture. Also, the viewcontroller which is presenting the imagepicker is a different Swift file
I had the same problem and I've found a solution, so I'm posting my version (I'm taking a picture from the photo library but it's the same :) ).
I had a memory management issue.
I've created an IBAction function where I instantiated my camera handler class (with the delegate inside...). At the end of the function the variable goes out of scope and it's deallocated. To solve the issue I've made it as instance variable.
That's my code for the VC with my UiButton:
class STECreateUserVC: UIViewController {
#IBOutlet weak var imgAvatar: UIImageView!
let cameraHandler = STECameraHandler()
#IBAction func buttonPressed(_ sender: UIButton) {
cameraHandler.importPictureIn(self) { [weak self] (image) in
self?.imgAvatar.image = image
}
}
}
...and that's my handler:
class STECameraHandler: NSObject {
let imagePickerController = UIImagePickerController()
var completitionClosure: ((UIImage) -> Void)?
func importPictureIn(_ viewController: UIViewController, completitionHandler:((UIImage) -> Void)?) {
completitionClosure = completitionHandler
imagePickerController.delegate = self
imagePickerController.allowsEditing = true
imagePickerController.sourceType = .photoLibrary
imagePickerController.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
viewController.present(imagePickerController, animated: true, completion: nil)
}
}
extension STECameraHandler: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let completitionClosure = completitionClosure, let image = info[UIImagePickerControllerEditedImage] as? UIImage {
completitionClosure(image)
}
imagePickerController.dismiss(animated: true)
}
}
I've used a closure in order to have a cleaner code.
This:
self.viewController.present(imagePicker, animated: true, completion: nil)
should be:
self.present(imagePicker, animated: true, completion: nil)

Select video from PhotoLibrary in iOS using Swift

I am trying to select video from PhotoLibrary using following code
imageController.mediaTypes = [kUTTypeMovie: NSString]
After selecting video, when it is compressing, I am getting array out of boundary issue.
I searched online and found following line. I am unable to convert it into Swift version (link)
imageController.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, nil]
Please let us know the Swift version for above line. It is very useful if anyone can provide Swift version of this.
Question2:
I want to show selected video in app and need to play when it is tapped. Can we do it without external plugins and using built in libraries?
Based on Swift 2.2
Suppose you have a imagePickerController and when you want to select both images and videos:
let imagePickerController = UIImagePickerController()
var videoURL: NSURL?
#IBAction func selectImageFromPhotoLibrary(sender: UIBarButtonItem) {
imagePickerController.sourceType = .PhotoLibrary
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.image", "public.movie"]
presentViewController(imagePickerController, animated: true, completion: nil)
}
Then after the video is selected, print out its NSURL.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
videoURL = info["UIImagePickerControllerReferenceURL"] as? NSURL
print(videoURL)
imagePickerController.dismissViewControllerAnimated(true, completion: nil)
}
For question 2:
Yes, you can do it through AVPlayer, you need import AVKit and AVFoundation, and you code may look like this:
if let videoURL = videoURL{
let player = AVPlayer(URL: videoURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
presentViewController(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
I made a demo here you can refer, maybe not 100% what you want.
#IBOutlet weak var imgView: UIImageView!
var imagePickerController = UIImagePickerController()
var videoURL : NSURL?
#IBAction func btnSelectVideo_Action(_ sender: Any) {
imagePickerController.sourceType = .savedPhotosAlbum
imagePickerController.delegate = self
imagePickerController.mediaTypes = [kUTTypeMovie as String]
present(imagePickerController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
videoURL = info[UIImagePickerControllerMediaURL]as? NSURL
print(videoURL!)
do {
let asset = AVURLAsset(url: videoURL as! URL , options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(0, 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
imgView.image = thumbnail
} catch let error {
print("*** Error generating thumbnail: \(error.localizedDescription)")
}
self.dismiss(animated: true, completion: nil)
}
For question 2:
let player = AVPlayer(url: videoURL)
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true) {
player.play()
}
Swift 5+ solution:
func openVideoGallery() {
picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .savedPhotosAlbum
picker.mediaTypes = ["public.movie"]
picker.allowsEditing = false
present(picker, animated: true, completion: nil)
}
Swift 3
import MobileCoreServices
var imagePickerController = UIImagePickerController()
var videoURL: URL?
private func openImgPicker() {
imagePickerController.sourceType = .savedPhotosAlbum
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.movie"]
present(imagePickerController, animated: true, completion: nil)
}
extension YourViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
videoURL = info[UIImagePickerControllerMediaURL] as? URL
print("videoURL:\(String(describing: videoURL))")
self.dismiss(animated: true, completion: nil)
}
}
func openCamera() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
println("captureVideoPressed and camera available.")
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .Camera
imagePicker.mediaTypes = [kUTTypeMovie!]
imagePicker.allowsEditing = false
imagePicker.showsCameraControls = true
self.presentViewController(imagePicker, animated: true, completion: nil)
} else {
println("Camera not available.")
}
}
func imagePickerController( didFinishPickingMediaWithInfo info:NSDictionary!) {
videoUrl = info[UIImagePickerControllerMediaURL] as! NSURL!
let pathString = videoUrl.relativePath
self.dismissViewControllerAnimated(true, completion: nil)
}
Swift 4.0
Your class adopts the UIImagePickerControllerDelegate protocol
class classname: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate
After that you need to create
let imagePickerController = UIImagePickerController()
Add this in your button's action:-
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.image", "public.movie"]
present(imagePickerController, animated: true, completion: nil)
Delegate method
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let videoURL = info["UIImagePickerControllerReferenceURL"] as? NSURL
print(videoURL!)
imagePickerController.dismiss(animated: true, completion: nil)
}
Select a Video from Gallery using Swift 4
// Put this code where you want to pick the video from gallery
Let imagePickerController = UIImagePickerController ()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
imagePickerController.mediaTypes = ["public.movie"]
present(imagePickerController, animated: true, completion: nil)
// UIImagePickerController Delegate Method
func imagePickerController (_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any])
{
let videoURL = info[UIImagePickerControllerMediaURL] as? NSURL
print(videoURL!)
self.dismiss(animated: true, completion: nil)
}
try this pod that i've made :
https://github.com/jhonyourangel/ImagePickerWhatsApp
I was searching for a similar Image and Video Picker for a project and i wasn't able to find one that was able to :
1. Take picture
2. Get a Picture from the library
3. Register a Video
4. Get a video from the library
While i was looking i hopen whatsup of facebook or mabe google have a pod for this kind of needs, i realy liked the whatsapp picker, so i created this one similer to the one in whatsapp.
Prerequisites
In order to use ImageVideoPicker you need cocoapods and an xCode project already created
Installing
to install cocoapods is should be enough just to run sudo gem install cocoapods in the terminal
if this doen't work go to cocoapods
Then navigate the terminal to your project folder, where the file extension .xcodeproj is located and run pod init
this will create a file called Podfile
Open the file in a editor ( sublimeText, xCode, atom, vim ... etc ) and add the line bellow after use_frameworks!
pod 'ImagePickerWhatsApp'
or
pod 'ImagePickerWhatsApp', :path => '/Users/aiu/Documents/cocoapods/ImagePickerWhatsApp'
then just run pod install in the terminal and wait to finish instaling the lib
How to use it
add import ImagePickerWhatsApp to your viewcontroller class
then you can call the picker by calling :
let mp = ImageVideoPicker.makeVCFromStoryboard()
self.present(mp, animated: true, completion: nil)
Delegate
to implement the delegate add mp.delegate = self and the extent the class of you view controller
aso you need to import the iOS Photos framework import Photos
extension ViewController: ImageVideoPickerDelegate {
func onCancel() {
print("no picture selected")
}
func onDoneSelection(assets: [PHAsset]) {
print("selected \(assets.count) assets")
}
}
the func onDoneSelection returns an array of assets that contain the info of where the asset is located : on the device, iTunes library or iCloud.
if you just need to display the images you can use the this code in a collection view or something similar just implement this peace of code
var representedAssetIdentifier: String!
func getImageFrom(asset: Phasset) {
representedAssetIdentifier = asset?.localIdentifier
let imageManager = PHCachingImageManager()
imageManager.requestImage(for: asset!, targetSize: self.frame.size, contentMode: .default, options: nil) { (image, _) in
if(self.representedAssetIdentifier == self.asset?.localIdentifier &&
image != nil) {
self.imageView.image = image
}
}
}
this will show just the thumbnail, but is awesome because is also showing the thumbnail for live photos, and videos
Images and Videos as Data
The lib is intended to be used for sending images or videos over the network, and not to do fancy image or video editing. But this doesn't mea you can't. You can do just about anything since it returns an array of assets, but is you job to implement what you need.
in order to get the data from the asset ImageVideoPicker has one method that will return an completition handler with the data.
ImageVideoPicker.getDataFrom(asset: asset) { (data) in
if data == nil {
print(data as Any, asset.mediaType, asset.localIdentifier)
} else {
print(data!.count as Any, asset.mediaType, asset.localIdentifier)
}
}
that will be all
have fun
func startMediaBrowserFromViewController(viewController: UIViewController!, usingDelegate delegate : protocol<UINavigationControllerDelegate, UIImagePickerControllerDelegate>!) -> Bool {
if UIImagePickerController.isSourceTypeAvailable(.SavedPhotosAlbum) == false {
return false
}
let mediaUI = UIImagePickerController()
mediaUI.sourceType = .SavedPhotosAlbum
mediaUI.mediaTypes = [kUTTypeMovie as String]
mediaUI.allowsEditing = true
mediaUI.delegate = delegate
presentViewController(mediaUI, animated: true, completion: nil)
return true
}
Updated for the current version of Swift:
// Check if the asset is of video media type.
guard (asset.mediaType == PHAssetMediaType.video) else {
print("Not a valid video media type")
return
}
// Obtain the URL of the video.
PHCachingImageManager().requestAVAsset(forVideo: asset, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
let asset = asset as! AVURLAsset
print("asset.url: ", asset.url) // Here is video URL
// Play the video.
DispatchQueue.main.async(execute: {
let player = AVPlayer(url: asset.url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
})
})
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
println("Camera Available")
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
Delegate method
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: NSDictionary!) {
self.dismissViewControllerAnimated(true, completion: nil)
imageView.image = image
}

Resources