I can't choose an image in UIImagePickerController. When I press on choose button my picker is not interactive anymore. I can only dismiss it. Here is what im getting in error log
UpdatedWebantGallery[75511:6760388] [xpc.exceptions] <NSXPCConnection: 0x6000025c2d00> connection on anonymousListener or serviceListener from pid 75514: Warning: Exception caught during invocation of selector didSelectMediaWithInfoDictionary:, dropping incoming message and invalidating the connection.
Exception: *** -[NSURL URLByAppendingPathExtension:]: component, components, or pathExtension cannot be nil.
*** -[NSURL URLByAppendingPathExtension:]: component, components, or pathExtension cannot be nil.
And Here is my code of ViewController
class AddPhotoSceneViewController: UIViewController {
internal var presenter: AddPhotoScenePresenter!
#IBOutlet weak var imageView: UIImageView!
let picker = UIImagePickerController()
let tapGestureRecgonizer = UITapGestureRecognizer()
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
override func viewDidLoad() {
super.viewDidLoad()
tapGestureRecgonizer.addTarget(self, action: #selector(showAlertSheet))
imageView.addGestureRecognizer(tapGestureRecgonizer)
setupAlert()
self.setLeftNavBarCancelButtonView(target: self, selector: #selector(self.returnToGalleryScreenTab))
}
func setupAlert() {
let uploadFromCameraAction = UIAlertAction(title: "Upload photo from camera", style: .default) { (action) in
self.picker.sourceType = .camera
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
if response {
//access granted
} else {
}
}
self.invokePicker()
}
let uploadFromGalleryAction = UIAlertAction(title: "Upload photo from gallery", style: .default) { (action) in
self.picker.sourceType = .photoLibrary
switch PHPhotoLibrary.authorizationStatus(){
case .authorized:
self.invokePicker()
case .denied:
let modalView = ModalPopUpViewController(title: "Access Denied",
text: "If you want to upload your own photo we need your access to open gallery",
buttontext: "Open Settings",
action: #selector(self.openSettings),
target: self)
self.present(modalView, animated: true, completion: nil)
default:
return
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
return
}
self.actionSheet.addAction(uploadFromCameraAction)
self.actionSheet.addAction(uploadFromGalleryAction)
self.actionSheet.addAction(cancelAction)
}
#objc func dismissModalView() {
self.dismiss(animated: true, completion: nil)
}
#objc func openSettings() {
self.dismiss(animated: true, completion: nil)
if let url = URL.init(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
#objc func showAlertSheet() {
self.present(self.actionSheet, animated: true) {
return
}
}
#objc func routeToAddPhotoForm() {
self.presenter?.routeToAddPhotoForm(image: self.imageView.image!)
}
#objc func returnToGalleryScreenTab() {
self.tabBarController?.selectedIndex = 0
}
func invokePicker() {
self.picker.allowsEditing = true
self.picker.delegate = self
self.present(self.picker, animated: true)
}
}
extension AddPhotoSceneViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.editedImage] as? UIImage else { return }
let imageName = UUID().uuidString
let imagePath = getDocumentsDirectory().appendingPathComponent(imageName)
if let jpegData = image.jpegData(compressionQuality: 0.8) {
try? jpegData.write(to: imagePath)
}
self.imageView.image = image
self.setRightNavBarButtonView(title: "Next",target: self, selector: #selector(self.routeToAddPhotoForm))
dismiss(animated: true)
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
}
I Have no idea why it can be happening.
Here is a screen where I'm getting stopped
Copy/pasting your implementation here -
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.editedImage] as? UIImage else {
// Add a print statement here to check whether we are returning from here
print("Could not find editedImage")
// if you are returning from here, then `dismiss` call at the end is not being executed
// hence your picker never gets dismissed
// try using info[.originalImage] in case you end up here
return
}
let imageName = UUID().uuidString
let imagePath = getDocumentsDirectory().appendingPathComponent(imageName)
if let jpegData = image.jpegData(compressionQuality: 0.8) {
try? jpegData.write(to: imagePath)
}
self.imageView.image = image
self.setRightNavBarButtonView(title: "Next",target: self, selector: #selector(self.routeToAddPhotoForm))
dismiss(animated: true)
}
When Cancel is pressed, UIImagePickerController.imagePickerControllerDidCancel(_:) is called.
Your delegate’s implementation of this method should dismiss the picker view by calling the dismissModalViewControllerAnimated: method of the parent view controller.
Implementation of this method is optional, but expected.
You should copy/paste following method to your code.
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
}
Related
I already worked on UIImagePickerController. This code was already works fine in Xcode 11.3. But when I run on Xcode 12 Image picker delegate is not calling in Xcode12.
/// Picked Image
struct PickedImage {
var image: UIImage?
var api: String?
}
/// Image picker
class ImagePicker: NSObject {
typealias ImagePickerHandler = ((_ selected: PickedImage) -> ())
private weak var presentationController: UIViewController?
let pickerController: UIImagePickerController = UIImagePickerController()
var apiKey: String?
private var handler: ImagePickerHandler? = nil
private func action(for type: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else {
return nil
}
return UIAlertAction(title: title, style: .default) { (action) in
DispatchQueue.main.async {
self.pickerController.mediaTypes = ["public.image"]
self.pickerController.sourceType = type
self.pickerController.delegate = self
self.presentationController?.present(self.pickerController, animated: true, completion: {
})
}
}
}
/// Present source view
/// - Parameter sourceView: view
func present(presentationController: UIViewController, completed: ImagePickerHandler? = nil) {
self.handler = completed
self.presentationController = presentationController
// self.delegate = delegate
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if let action = self.action(for: .camera, title: "Take photo") {
alertController.addAction(action)
}
if let action = self.action(for: .savedPhotosAlbum, title: "Camera roll") {
alertController.addAction(action)
}
if let action = self.action(for: .photoLibrary, title: "Photo library") {
alertController.addAction(action)
}
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
// if UIDevice.current.userInterfaceIdiom == .pad {
// alertController.popoverPresentationController?.sourceView = sourceView
// alertController.popoverPresentationController?.sourceRect = sourceView.bounds
// alertController.popoverPresentationController?.permittedArrowDirections = [.down, .up]
// }
self.presentationController?.present(alertController, animated: true)
}
private func pickerController(didSelect image: UIImage?, imageURL: URL?) {
pickerController.dismiss(animated: true, completion: nil)
// self.delegate?.imagePicker(picker: self, didSelected: image, apikey: apiKey)
handler?(PickedImage(image: image, api: apiKey))
}
}
/// ImagePicker controller delegate
extension ImagePicker: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.pickerController(didSelect: nil, imageURL: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.pickerController(didSelect: info[.originalImage] as? UIImage, imageURL: info[.imageURL] as? URL)
}
}
When I check delegate is applied or not using breakpoint. like in console means
po imagepicker.delegate
there after image picker delegate was working fine. But when I remove breakpoint its delegate is not calling.
I don't know what is the reason. Why its not working. May I know how to fix this problem.
is there any reason to not put pickerController.delegate = self before self.presentationController?.present(pickerController, animated: true, completion: {})'?
if no, maybe you can put pickerController.delegate = self before that, and try again.
This is most likely because you're not retaining your picker controller in a variable. As soon as your function finishes, it gets deallocated.
For example I have something like this:
class MyClass: UIImagePickerControllerDelegate {
let imagePicker = UIImagePickerController()
}
func pickImageFromGallery() {
self.imagePicker.delegate = self
self.imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
self.imagePicker.allowsEditing = false
self.present(self.imagePicker, animated: true, completion: nil)
}
... and the delegate methods as well
You code was always wrong; it's just lucky if it ever worked:
let pickerController: UIImagePickerController = UIImagePickerController()
pickerController.mediaTypes = ["public.image"]
pickerController.sourceType = "Photo library"
self.presentationController?.present(pickerController, animated: true, completion: {
pickerController.delegate = self
})
Change to:
let pickerController: UIImagePickerController = UIImagePickerController()
pickerController.mediaTypes = ["public.image"]
pickerController.sourceType = .photoLibrary
pickerController.delegate = self
self.present(pickerController, animated: true)
I think you are doing a silly mistake. just change a few lines of code and then you are good to go.
just follow my Steps
=> Here ProfileViewController is my UIViewController where I am going to pick Image from Gallery and Set image to UIImageView. You have to use your UIViewController where you want to Pick an Image.
ProfileViewController: UIViewController{
let pickerController = UIImagePickerController()
viewDidLoad(){
}
#IBAction func pickImageAction(sender: UIButton){
self.openImagePicker()
}
func openImagePicker()
{
pickerController.delegate = self
pickerController.allowsEditing = true
pickerController.mediaTypes = ["public.image", "public.movie"]
pickerController.sourceType = .photoLibrary // Pick image from PhotoLibrary
//pickerController.sourceType = .savedPhotosAlbum // Pick Saved Images
//pickerController.sourceType = .camera // Click Image using Camera
self.present(pickerController, animated: true)
} //End of setupImagePicker
} // End of ProfileViewController
// MARK:- Delegate method for UIImagePicker
extension ProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.editedImage] as? UIImage else { return }
// image is your image which you picked from Image Gallery or using Camera.
// you can set this image directly to your UIImageView.
// self.yourImageView.image = image
// or you can compress this image, converting to JPG image type.
// compressionQuality will reduce your image quality and Image Size.
if let jpegData = image.jpegData(compressionQuality: 0.8) {
// you can use this compressed image.
}
self.dismiss(animated: true)
}// End of didFinishPickingMediaWithInfo
} // End of Extension
I am trying to upload a video from my library to Firebase storage in my application, but it seems to be resulting in an error. This does not happen if the video has been captured using UIImagePicker, it only happens when the user pickes an already taken video. I am using XCode 11.0 beta (11M336w) and iOS 13 beta 3.
My ImagePicker class:
import UIKit
import AVFoundation
import CropViewController
public protocol ImagePickerDelegate: class {
func didSelect(image: UIImage?)
func didSelect(fileUrl: URL)
}
open class ImagePicker: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate, CropViewControllerDelegate {
private let pickerController: UIImagePickerController
private weak var presentationController: UIViewController?
private weak var delegate: ImagePickerDelegate?
private var editing = false
private var croppingStyle: CropViewCroppingStyle!
public init(presentationController: UIViewController, delegate: ImagePickerDelegate, editing: Bool, croppingStyle: CropViewCroppingStyle, mediaTypes: [String]?) {
self.pickerController = UIImagePickerController()
super.init()
self.presentationController = presentationController
self.delegate = delegate
self.pickerController.delegate = self
self.editing = editing
self.croppingStyle = croppingStyle
if let mediaTypes = mediaTypes {
self.pickerController.mediaTypes = mediaTypes
} else if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .camera) {
self.pickerController.mediaTypes = mediaTypes
}
self.pickerController.sourceType = .camera
self.pickerController.showsCameraControls = true
self.pickerController.videoQuality = .typeHigh
self.pickerController.navigationBar.titleTextAttributes = nil
self.pickerController.navigationItem.rightBarButtonItem?.setTitleTextAttributes(nil, for: .normal)
self.pickerController.navigationItem.rightBarButtonItem?.setTitleTextAttributes(nil, for: .highlighted)
}
private func action(for type: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else {
return nil
}
return UIAlertAction(title: title, style: .default) { [unowned self] _ in
self.pickerController.sourceType = type
self.presentationController?.present(self.pickerController, animated: true)
}
}
public func present(from sourceView: UIView) {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if let action = self.action(for: .camera, title: "Take photo or video") {
alertController.addAction(action)
}
if let action = self.action(for: .photoLibrary, title: "Choose from library") {
alertController.addAction(action)
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
cancel.setValue(UIColor.red, forKey: "titleTextColor")
alertController.addAction(cancel)
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.popoverPresentationController?.sourceView = sourceView
alertController.popoverPresentationController?.sourceRect = sourceView.bounds
alertController.popoverPresentationController?.permittedArrowDirections = [.down, .up]
}
self.presentationController?.present(alertController, animated: true)
}
private func pickerController(_ controller: UIImagePickerController, didSelect image: UIImage?) {
self.delegate?.didSelect(image: image)
controller.dismiss(animated: true, completion: nil)
}
private func pickerController(_ controller: UIImagePickerController, didSelectVideo videoUrl: URL) {
self.delegate?.didSelect(fileUrl: videoUrl)
controller.dismiss(animated: true, completion: nil)
}
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.pickerController(picker, didSelect: nil)
}
var picker: UIImagePickerController!
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let videoUrl = info[.mediaURL] as? URL {
self.pickerController(picker, didSelectVideo: videoUrl)
return
}
if let image = info[.originalImage] as? UIImage {
if editing {
let cropViewController = CropViewController(croppingStyle: croppingStyle, image: image)
cropViewController.delegate = self
self.picker = picker
self.presentationController?.present(cropViewController, animated: true, completion: nil)
} else {
self.pickerController(picker, didSelect: image)
}
} else {
self.pickerController(picker, didSelect: nil)
}
}
public func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
self.pickerController(picker, didSelect: image)
}
}
I present the viewcontroller with the following function inside my UITableView class (I just call this function when a button has been pressed):
func choose() {
let imagePicker = ImagePicker(presentationController: self, delegate: self, editing: false, croppingStyle: .default, mediaTypes: nil)
imagePicker.present(from: view)
}
Then in the imagepicker delegate I use this code:
func didSelect(image: UIImage?) {
//
}
func didSelect(fileUrl: URL) {
let uuid = NSUUID().uuidString
let path = uuid + "." + fileUrl.pathExtension
let uploadTask = Storage.storage().reference(withPath: "message_videos/\(path)").putFile(from: fileUrl, metadata: nil) { (metadata, error) in
if let error = error {
print(error)
return
}
print("success!")
}
}
When executed, this results in the following console prints:
2019-07-05 23:41:31.967623+0200 APPLICATION_NAME[9491:1007368] Failed to issue sandbox extension for file file:///private/var/mobile/Containers/Data/PluginKitPlugin/8B54AF9B-6618-4341-85DE-2EAC29198B17/tmp/trim.FEF41C1D-7D43-4E95-84A1-36AC99FEDE14.MOV, errno = 1
2019-07-05 23:41:31.982082+0200 APPLICATION_NAME[9491:1007368] Task <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1> finished with error [-1] Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSErrorFailingURLStringKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, NSErrorFailingURLKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>, NSLocalizedDescription=unknown error}
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response." UserInfo={bucket=XXXXXXXXXXXXXXXXXXXXXXX.appspot.com, _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>, object=message_videos/BB2CB773-982B-4800-9398-B2F96ED91B6D.MOV, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>"
), NSLocalizedDescription=An unknown error occurred, please check the server response., ResponseErrorDomain=NSURLErrorDomain, NSErrorFailingURLStringKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, NSErrorFailingURLKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, ResponseErrorCode=-1}
Is there a way to resolve this?
So I was able to solve this issue in my app by converting the video to Data and uploading that using the putData function from Firebase Storage API.
I'm not exactly sure why this change was necessary with iOS 13, but I hope this helps.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//ensure user picked a video and you have the URL
guard let mediaType = info[.mediaType] as? String, mediaType == "public.movie", let movieURL = info[.mediaURL] as? URL else {
dismiss(animated: true)
return
}
uploadVideo(url: movieURL)
//continue code your here...
}
private func uploadVideo(url: URL) {
do {
//convert video to Data
let videoData = try Data(contentsOf: movieURL)
//build storage "path"
let uniqueID = UUID().uuidString
let path = "message_videos/" + uniqueID
let storageRef = Storage.storage().reference().child(path)
//use metadata to specify it's a video
let uploadMetadata = StorageMetadata()
uploadMetadata.contentType = "video/quicktime"
//upload via putData
let uploadTask = storageRef.putData(videoData, metadata: uploadMetadata) { (metadata, error) in
if let error = error {
//handle upload error
} else {
//successful upload
}
} catch {
//handle video -> Data error
}
}
}
I want to bind my ImageView to viewModel for save my selected image to Core Data.
My code look like this:
class FoodViewModel: FoodViewModelType {
var foodImage: BehaviorRelay<UIImage?>
//... another code
}
My controller:
class NewFoodViewController: UIViewController {
#IBOutlet weak var foodImageView: UIImageView!
override func viewDidLoad() {
//... another code
self.foodImageView.rx.image.bind(to: foodViewModel.foodImage).disposed(by: self.disposeBag)
}
}
And i get error:
Value of type Binder < UIImage? > has no member 'bind'
How to save my image to Core Data with good MVVM practice?
Update
I am choose photo in view controller:
func chooseImagePickerAction(source: UIImagePickerController.SourceType) {
if UIImagePickerController.isSourceTypeAvailable(source) {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = source
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
}
#objc func foodImageViewTapped(_ sender: AnyObject) {
let alertController = UIAlertController(title: "Photo path", message: nil, preferredStyle: .actionSheet)
let cameraAction = UIAlertAction(title: "Camera", style: .default) { (action) in
self.chooseImagePickerAction(source: .camera)
}
let photoLibAction = UIAlertAction(title: "Photo", style: .default) { (action) in
self.chooseImagePickerAction(source: .photoLibrary)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default)
alertController.addAction(cameraAction)
alertController.addAction(photoLibAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
extension NewFoodViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
foodImageView.image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)] as? UIImage
foodImageView.contentMode = .scaleAspectFill
dismiss(animated: true, completion: nil)
}
private func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] {
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}
private func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
return input.rawValue
}
}
And in viewDidLoad (without image):
saveNewFoodBarButtonItem.rx.tap.subscribe(onNext: { [weak self] _ in
guard let self = self else { return }
let foodViewModel = FoodViewModel()
self.foodQuantityTypeTextField.rx.text.bind(to: foodViewModel.foodQuantityType).disposed(by: self.disposeBag)
self.foodShelfLifeTextField.rx.text.bind(to: foodViewModel.foodShelfLife).disposed(by: self.disposeBag)
self.foodCategoryTextField.rx.text.bind(to: foodViewModel.foodCategoryId).disposed(by: self.disposeBag)
self.foodQuantityTextField.rx.text.bind(to: foodViewModel.foodQuantity).disposed(by: self.disposeBag)
self.foodNameTextField.rx.text.bind(to: foodViewModel.foodName).disposed(by: self.disposeBag)
foodViewModel.saveNewFood(fridgeViewModel: self.fridgeViewModel!)
self.dismiss(animated: true)
}).disposed(by: disposeBag)
UIImageView is not bindable because it is an output view, not an input view, i.e., you push things into it, it doesn't push things out.
In order to emit an image to your view model, you need to do it the at the point where you push the image into the UIImageView.
I have a project that requires me to take a picture and send it to the provided API. I don't want to save it locally, the picture of the image should be sent to the API immediately once the picture is captured.
I've checked the Stack Overflow question swift Take a photo and save to photo library, but it seems like the image is stored locally.
Here's my code:
func cameraSetup(){
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
do {
let input = try AVCaptureDeviceInput(device: captureDevice!)
captureSession = AVCaptureSession()
captureSession?.addInput(input)
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
videoPreviewLayer?.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height - 150)
self.cameraView.layer.addSublayer(videoPreviewLayer!)
captureSession?.startRunning()
} catch {
print(error)
}
}
}
How can I send it off immediately instead of having to save it locally first?
For task like this, you should consider using UIImagePickerController and its Delegate methods. Best practice for this is to show user options to choose between camera and gallery (Photo library).
class MyViewController: UIViewController {
func presentImagePickerActionSheet() {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
func addCameraAction() {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else { return assertionFailure("No camera") }
let pickerAction = UIAlertAction(title: "Camera", style: .default) { _ in
self.pickImage(source: .camera)
}
actionSheet.addAction(pickerAction)
}
func addGalleryPickerAction() {
guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else { return assertionFailure("No gallery") }
let pickerAction = UIAlertAction(title: "Gallery", style: .default) { _ in
self.pickImage(source: .photoLibrary)
}
actionSheet.addAction(pickerAction)
}
func addRemoveActionIfNeeded() {
return() // Do your logic if needed
let pickerAction = UIAlertAction(title: "Delete", style: .destructive) { _ in
}
actionSheet.addAction(pickerAction)
}
func addCancelAction() {
let cancelAction = UIAlertAction(title: "cancel", style: .cancel, handler: nil)
actionSheet.addAction(cancelAction)
}
addCameraAction()
addGalleryPickerAction()
addRemoveActionIfNeeded()
addCancelAction()
present(actionSheet, animated: true)
}
private func pickImage(source: UIImagePickerControllerSourceType) {
guard UIImagePickerController.isSourceTypeAvailable(source) else { return assertionFailure("Source not found") }
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = source
imagePickerController.delegate = self
imagePickerController.allowsEditing = true
present(imagePickerController, animated: true)
}
}
extension MyViewController: UIImagePickerControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
defer { picker.dismiss(animated: true) }
let editedImage = info[UIImagePickerControllerEditedImage]
let originalImage = info[UIImagePickerControllerOriginalImage]
guard let image = (editedImage ?? originalImage) as? UIImage else { return assertionFailure("Image not found")}
// Do anything you want with image here
// In case of need to convert it to data:
let quality = 1.0
guard let imageData = UIImageJPEGRepresentation(image, quality) else { return assertionFailure("No image data") }
// Do anything you want with image data here
}
}
I am trying to have a user choose an image from their gallery or camera, then upload it to the app. This works, but the only problem is that it doesn't save it in the app. As soon as the user closes the app, the image that the user chose disappears. I also do not have any save function because i don't know how to implement one.
I am using Xcode 8.3.2 in Swift 3.0. Here is the code below:
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func chooseImage(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("Camera not available")
}
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
picker.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Remember to save image you need to store image as NSData
// Code to store image
let defaults = UserDefaults.standard
// To save as data:
// From StoryBoard, if you want to save "image" data on the imageView of
// MainStoryBoard, following codes will work.
let image = UIImagePNGRepresentation(imageView.image!) as NSData?
defaults.set(image, forKey: "test") // saving image into userdefault
// for retrieving the image
if (UserDefaults.standard.object(forKey: "test") as? NSData) != nil {
let photo = UserDefaults.standard.object(forKey: "test") as! NSData
img2.image = UIImage(data: photo as Data) // img2 set your imageview on which you want photo to appear
// Now you can set img2.image
}
Edited
How to use in your code
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any]) {
let defaults = UserDefaults.standard
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
let saveImage = UIImagePNGRepresentation(image!) as NSData?
defaults.set(saveImage, forKey: "test") // saving image into userdefault
picker.dismiss(animated: true, completion: nil)
}
And in your view did load use retrieving method
If the image exist and in nsdata format then only it will show save image. Thats it.
You can save image in your document directory with below function
func saveImageDocumentDirectory(tempImage:UIImage){
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = documentsDirectoryURL.appendingPathComponent("ImageName.png")
do {
try UIImagePNGRepresentation(tempImage)?.write(to: fileURL)
} catch {
print(error)
}
}
To retrieve Image you can use
func getImage()->URL?{
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = documentsDirectoryURL.appendingPathComponent("ImageName.png")
if FileManager.default.fileExists(atPath: fileURL.path){
return fileURL
}else{
return nil
}
}
You can use any name you like and store image with different name to store multiple image.