I am trying to take a printed item and inserting it into my Firebase Database along with the rest of outlets. Thanks!
#objc(imagePickerController:didFinishPickingMediaWithInfo:) func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView.image = image
} else {
//error
}
self.dismiss(animated: true, completion: nil)
let storageRef = FIRStorage.storage().reference().child("myImage.png")
if let uploadData = UIImagePNGRepresentation(self.myImageView.image!) {
storageRef.put(uploadData, metadata: nil, completion:
{
(metadata, error) in
if error != nil {
print("error")
return
} else {
print((metadata?.downloadURL()?.absoluteString)!)
//i want to take the line above and insert it into the database
}
})
}
}
#IBAction func addPost(_ sender: Any) {
if self.titleText.text != "" && self.authorText.text != "" && self.mainText.text != "" && self.dateText.text != "" {
ref?.child("Posts").childByAutoId()
.setValue(["Title": titleText.text,
"Article": mainText.text,
"Author": authorText.text,
"Date": dateText.text ])
//insert the download URL above
self.performSegue(withIdentifier: "kost", sender: self)
}
}
I see what your problem is now. You are tackling uploading images to firebase in totally the wrong manner. In the event didFinishPickingMediaWithInfo you should not be doing anything with firebase. You should only be setting your UIImageViews image to store the value of the data given from the image picker.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
self.dismiss(animated: true, completion: nil)
if let editedImage = info[UIImagePickerControllerEditedImage] as? UIImage{
myImageView.image = editedImage
}else{
print("Something went wrong")
}
}
Then in your IBAction, you should upload everything to firebase. Here is a simple function that will upload your image to the database it:
func uploadImage(){
if let fileData = UIImageJPEGRepresentation(myImageView.image!, 0.8){
let storageRef = storage.reference().child("images").child("testImage.jpg")
storageRef.put(fileData, metadata: nil, completion: { (metadata, error) in
if error != nil{
print(error?.localizedDescription ?? "error")
return
}
let downloadURL = metadata?.downloadURL()?.absoluteString
// Write the download URL to your Database
self.ref?.child("images").setValue(downloadURL)
})
}else{
print("error")
}
}
Related
I've got a problem with updating data. As you can see on this picture below, when I change those three textfields but leave current image and tap "Save", it will update my data in Firebase but also will upload a NEW image which is EMPTY so user will see an empty UIImageView.
Why is that?
Change Medication view image
Change Medication view no image
This is my method from Firebase to save image(data) and download URL:
func saveImageToStorage(cellImage: Data, completion: #escaping(Result<String, Error>) -> Void) {
guard let uid = Auth.auth().currentUser?.uid else { return }
refStorage.child(uid).child(imageName).putData(cellImage, metadata: nil) { (_, error) in
guard error == nil else {
completion(.failure(NSError(domain: "Saving image to storage failed", code: 0)))
return
}
self.refStorage.child(uid).child(self.imageName).downloadURL { (url, error) in
guard let url = url, error == nil else { return }
let urlString = url.absoluteString
completion(.success(urlString))
print("URL downloaded: \(urlString)")
}
}
}
Here is extension with UIImagePickerControllerDelegate:
extension CurrentMedicationSettingsViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let compressionQualityValue: CGFloat = 0.1
let image = info[.originalImage] as? UIImage
userMedicationSettingView.medicationImageView.image = image
if let uploadData = image?.jpegData(compressionQuality: compressionQualityValue) {
imageData = uploadData
}
picker.dismiss(animated: true, completion: nil)
}
ViewModel where update medication method is:
func updateMedicationInfo(data: Data, pillName: String, capacity: String, dose: String, childId: String, completion: #escaping () -> Void) {
firebaseManager.saveImageToStorage(cellImage: data) { (result) in
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(let url):
self.firebaseManager.updateMedicationInfo(pillName: pillName, capacity: capacity, dose: dose, cellImageURL: url, childId: childId)
}
completion()
}
}
Thanks for any advice!
Cheers!
The code here allows me to upload and download one photo to Firebase and save it to user defaults but I'm trying to figure out how to do it within a collectionView cell and display as many photos wanted, adding on new items
import UIKit
import FirebaseStorage
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
private let storage = Storage.storage().reference()
#IBOutlet var imageView: UIImageView!
#IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
label.numberOfLines = 0
guard let urlString = UserDefaults.standard.value(forKey: "url") as? String, let url = URL(string: urlString) else {
return
}
label.text = urlString
let task = URLSession.shared.dataTask(with: url, completionHandler: { data,_,error in
guard let data = data, error == nil else {
return
}
DispatchQueue.main.async {
let image = UIImage(data: data)
self.imageView.image = image
}
})
task.resume()
}
#IBAction func didTapButton() {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
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 {
return
}
guard let imageData = image.pngData() else {
return
}
storage.child("Images/Photo.png").putData(imageData, metadata: nil) { (_, error) in
guard error == nil else {
print("Failed to Upload Data")
return
}
self.storage.child("Images/Photo.png").downloadURL(completion: {url, error in
guard let url = url, error == nil else {
return
}
let urlString = url.absoluteString
DispatchQueue.main.async {
self.label.text = urlString
self.imageView.image = image
}
print("Download URL: \(urlString)")
UserDefaults.standard.set(urlString, forKey: "url")
})
}
// Upload Image Data
// Get Download URL
// Save Download URL to userDefaults
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
To upload images to Firebase storage and show them in a collection view, you can use the following steps;
Set up collection view with an array of URLs (or Strings) as its
data source. You can use your custom models if required.
Keep a reference to your Firebase storage and upload the image. After successful upload, get the URL for the uploaded image using the image reference.
Save the url in Firebase Database(or Cloud Firestore). This is required only if you want to sync the collection view with the database and update it when new images are uploaded.
Add a listener to your Firebase database reference where you have
saved the image URLs. Update the local URLs array inside the listener and reload the collection view.
If you don't want to use Firebase database, omit steps 3 and 4, save the image URL to the array and reload the collection view right away.
I'm not adding the code for collection view setup here as it's not the objective of this answer.
let storageRef = Storage.storage().reference(withPath: "images")
let databaseRef = Database.database().reference(withPath:"images")
var images: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
addDatabaseListener()
}
private func addDatabaseListener() {
databaseRef.observe(.childAdded) { (snapshot) in
guard let value = snapshot.value as? [String: Any], let url = value["url"] as? String else { return }
self.images.append(url)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage, let data = image.jpegData(compressionQuality: 0.1) else { return }
let fileName = "\(Date.timeIntervalSinceReferenceDate).jpeg"
let newImageRef = storageRef.child(fileName)
newImageRef.putData(data, metadata: nil) { (_, error) in
if let error = error {
print("upload failed: ", error.localizedDescription)
return
}
newImageRef.downloadURL { (url, error) in
if let error = error {
print("error: ", error.localizedDescription)
return
}
self.databaseRef.childByAutoId().setValue(["url": url?.absoluteString])
}
}
}
I know this question has been asked before but none of the answers have fixed my issue. I'm getting the error:
Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}
I have another project where I'm using this exact method in another project that works perfectly fine. I have tried to place #objc in front of the functions but get this error:
Objective-C method imagePickerController:didFinishPickingMediaWithInfo: provided by method imagePickerController(_:didFinishPickingMediaWithInfo:) conflicts with optional requirement method imagePickerController(_:didFinishPickingMediaWithInfo:) in protocol UIImagePickerControllerDelegate.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let uid = Auth.auth().currentUser?.uid else { return }
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
let editImage = editedImage.withRenderingMode(.alwaysOriginal)
guard let uploadData = editImage.jpegData(compressionQuality: 0.3) else { return }
let filename = NSUUID().uuidString
let stoarageRef = Storage.storage().reference().child("profile_images").child(filename)
stoarageRef.putData(uploadData, metadata: nil) { (metadata, error) in
if let error = error {
print("Failed update profile image:", error)
}
stoarageRef.downloadURL(completion: { (downloadUrl, error) in
guard let profileImageUrl = downloadUrl?.absoluteString else { return }
print("Successfully updated image in storage:", profileImageUrl)
let dictionaryValues = ["profileImageUrl": profileImageUrl]
Database.database().reference().child("users").child(uid).updateChildValues(dictionaryValues, withCompletionBlock: { (error, ref) in
if let error = error {
print("There was an error:", error)
return
}
print("Successfully saved user info to db")
})
})
}
} else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
let origImage = originalImage.withRenderingMode(.alwaysOriginal)
guard let uploadData = origImage.jpegData(compressionQuality: 0.3) else { return }
let filename = NSUUID().uuidString
let stoarageRef = Storage.storage().reference().child("profile_images").child(filename)
stoarageRef.putData(uploadData, metadata: nil) { (metadata, error) in
if let error = error {
print("Failed update profile image:", error)
}
stoarageRef.downloadURL(completion: { (downloadUrl, error) in
guard let profileImageUrl = downloadUrl?.absoluteString else { return }
print("Successfully updated image in storage:", profileImageUrl)
let dictionaryValues = ["profileImageUrl": profileImageUrl]
Database.database().reference().child("users").child(uid).updateChildValues(dictionaryValues, withCompletionBlock: { (error, ref) in
if let error = error {
print("There was an error:", error)
return
}
print("Successfully saved user info to db")
})
})
}
}
dismiss(animated: true, completion: nil)
}
Thank you for any help fixing this issue.
Swift 5, Xcode 11
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
backgroundImage = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage)!
ivBackground.image = backgroundImage
picker.dismiss(animated: true, completion: nil)
}
This is not just Swift 5 problem. Type of info parameter for this delegate method was changed from [String : Any] to [UIImagePickerController.InfoKey : Any] a long time ago.
This is why compiler complains that your, in this case your own, method conflicts with method declared by implemented protocol.
So, you need to implement delegate's method with correct type of parameter
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
<#code#>
}
The new function name is what causes the error, it is confused with two different functions that do the same thing.
It used to be [String : Any] (which is what you have) but now they have changed it to [UIImagePickerController.InfoKey : Any]. This change just means that the info is going to be type of UIImagePickerController.InfoKey.
Try use this as your function name, it got changed a while ago (not in Swift 5):
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any])
Hope this helps!
I've got a problem regarding Firebase and the upload of pictures..
I've been tried to follow the Firebase doc but I'm not sur to do the right things ...
In my application I want to send in firebase the value of 2 textfields and 1 segmented control plus one picture which is coming from the iphone's gallery.
well my save button :
#IBAction func saveBtnWasPressed(_ sender: Any) {
//Informations from the segmented control
if isMe == false {// Si SE
acftType = "SE"
}else if isMe == true {//Si ME
acftType = "ME"
}
let ref = Database.database().reference()
let userID = Auth.auth().currentUser?.uid
let usersPlanes : NSDictionary = [ "Registration" : self.acftRegTxtField.text!,
"model": self.acftModelTxtField.text!,
"Type" : self.acftType]
if isMe == false {// Si SE
ref.child("Planes").child(userID!).child("SE").childByAutoId().setValue(usersPlanes)
}else if isMe == true {//Si ME
ref.child("Planes").child(userID!).child("ME").childByAutoId().setValue(usersPlanes)
}else{
print("Error: Impossible to find the type of aircraft...")
}
let Dpalert = UIAlertController(title: nil, message: "Your informations as been upload", preferredStyle: .alert)
Dpalert.addAction(UIAlertAction(title: "Roger", style: .cancel, handler: nil))
self.present(Dpalert, animated: true)
}
And my function to allow user to select an image from his gallery is :
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let userID = Auth.auth().currentUser?.uid
self.dismiss(animated: true, completion: nil)
if let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
self.planImageView.image = selectedImage
var data = Data()
data = selectedImage.jpegData(compressionQuality: 0.75)!
}else{
print("Error : Impossible to deal with this image...")
}
let imageRef = Storage.storage().reference().child("Images").child(userID!).child(randomString(20));
let uploadPict = imageRef.putData(data, metadata: nil){ (metadata, error) in
guard let metadata = metadata else {
return
}
let size = metadata.size
imageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
return
}
}
}
But nothing appears in firebase when the picture is load in the app and How can I add it in the same folder as my first 3 information send with the save button ?
I'm totally lost with all this information. How can I solve my problem ?
Thanks very much for your help !
Flyer-74
In this function
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let userID = Auth.auth().currentUser?.uid
self.dismiss(animated: true, completion: nil)
if let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
self.planImageView.image = selectedImage
var data = Data()
data = selectedImage.jpegData(compressionQuality: 0.75)!
}else{
print("Error : Impossible to deal with this image...")
}
let imageRef = Storage.storage().reference().child("Images").child(userID!).child(randomString(20));
let uploadPict = imageRef.putData(data, metadata: nil){ (metadata, error) in
guard let metadata = metadata else {
return
}
let size = metadata.size
imageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
return
}
}
}
Try to put an output when your putData fail
let uploadPict = imageRef.putData(data, metadata: nil){ (metadata, error) in
guard let metadata = metadata else {
print("Error with upload \(String(describing: error?.localizedDescription))")
return
}
let size = metadata.size
imageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
print("Error with download URL: \(String(describing: error?.localizedDescription))")
return
}
}
Maybe it will help you to recognize the error; tell me what you got in the error
I have a UIImagePicker set up within my app that works fine. I would like to upload a profile picture to Firebase when my UIImage picker has been chosen. Here is my function for when a picture has been selected.
//image picker did finish code
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
profilePic.contentMode = .ScaleAspectFill
profilePic.image = chosenImage
profilePic.hidden = false
buttonStack.hidden = true
changeButtonView.hidden = false
self.statusLabel.text = "Here is Your Profile Picture"
dismissViewControllerAnimated(true, completion: nil)
}
The new documentation states that we need to declare a NSURl in order to upload a file. Here is my attempt to find the NSURL of the given file, but it doesn't work. Here is the documentation and a link to it:https://firebase.google.com/docs/storage/ios/upload-files#upload_from_data_in_memory
// File located on disk
let localFile: NSURL = ...
// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putFile(localFile, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL
}
}
Here is my attempt for retrieving the NSURL of the UIImagePicker:
//image picker did finish code
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
//getting the object's url
let imageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String;
let photoUrl = NSURL(fileURLWithPath: documentDir)
let localPath = photoUrl.URLByAppendingPathComponent(imageName!)
self.localFile = localPath
profilePic.contentMode = .ScaleAspectFill
profilePic.image = chosenImage
profilePic.hidden = false
buttonStack.hidden = true
changeButtonView.hidden = false
self.statusLabel.text = "Here is Your Profile Picture"
dismissViewControllerAnimated(true, completion: nil)
}
I believe that I am also running into difficulties if the image was taken from the camera instead of the gallery since it is not saved on the device yet. How do I find this image/snapshots's NSURL?
Here is my method to upload and download the user profile photo from firebase storage:
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
userPhoto.image = image
dismissViewControllerAnimated(true, completion: nil)
var data = NSData()
data = UIImageJPEGRepresentation(userPhoto.image!, 0.8)!
// set upload path
let filePath = "\(FIRAuth.auth()!.currentUser!.uid)/\("userPhoto")"
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
self.storageRef.child(filePath).putData(data, metadata: metaData){(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
}else{
//store downloadURL
let downloadURL = metaData!.downloadURL()!.absoluteString
//store downloadURL at database
self.databaseRef.child("users").child(FIRAuth.auth()!.currentUser!.uid).updateChildValues(["userPhoto": downloadURL])
}
}
}
I also store the Image URL into firebase database and check if the user has a profile photo or you might get a crash:
//get photo back
databaseRef.child("users").child(userID!).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// check if user has photo
if snapshot.hasChild("userPhoto"){
// set image locatin
let filePath = "\(userID!)/\("userPhoto")"
// Assuming a < 10MB file, though you can change that
self.storageRef.child(filePath).dataWithMaxSize(10*1024*1024, completion: { (data, error) in
let userPhoto = UIImage(data: data!)
self.userPhoto.image = userPhoto
})
}
})
Simple 2020 example
Don't forget to add pod 'Firebase/Storage' to your podfile, and pod install
Add two delegates to your class
class YourScreen: UIViewController,
UIImagePickerControllerDelegate, UINavigationControllerDelegate {
Storyboard, button, link to ...
#IBAction func tapCameraButton() {
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
and then
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let im: UIImage = info[.editedImage] as? UIImage else { return }
guard let d: Data = im.jpegData(compressionQuality: 0.5) else { return }
let md = StorageMetadata()
md.contentType = "image/png"
let ref = Storage.storage().reference().child("someFolder/12345678.jpg")
ref.putData(d, metadata: md) { (metadata, error) in
if error == nil {
ref.downloadURL(completion: { (url, error) in
print("Done, url is \(String(describing: url))")
})
}else{
print("error \(String(describing: error))")
}
}
dismiss(animated: true)
}
But where do you put the image?
At the code,
... .child("someFolder/12345678.jpg")
Almost inevitably,
• as the folder name use the user's id, the chat id, the feed id or a similar concept
• for the name, the only possibility is a uuid
Hence almost always
let f = chatId + "/" + UUID().uuidString + ".jpg"
let ref = Storage.storage().reference().child(f)
Working in Swift 4.2
Here i am doing click on image i have added tapGesture then it open gallery then selected image that upload in Firebase and also i add textField Value Too i hope it helps you Thank You
import UIKit
import Firebase
class ViewController: UIViewController {
#IBOutlet var myImageView: UIImageView!
#IBOutlet var txtText: UITextField!
var ref = DatabaseReference.init()
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.openGalleryClick(tapGesture:)))
myImageView.isUserInteractionEnabled = true
myImageView.addGestureRecognizer(tapGestureRecognizer)
myImageView.backgroundColor = UIColor.red
}
#objc func openGalleryClick(tapGesture: UITapGestureRecognizer){
self.setupImagePicker()
}
#IBAction func btnSaveClick(_ sender: UIButton) {
self.saveFIRData()
}
func saveFIRData(){
self.uploadMedia(image: myImageView.image!){ url in
self.saveImage(userName: self.txtText.text!, profileImageURL: url!){ success in
if (success != nil){
self.dismiss(animated: true, completion: nil)
}
}
}
}
func uploadMedia(image :UIImage, completion: #escaping ((_ url: URL?) -> ())) {
let storageRef = Storage.storage().reference().child("myimage.png")
let imgData = self.myImageView.image?.pngData()
let metaData = StorageMetadata()
metaData.contentType = "image/png"
storageRef.putData(imgData!, metadata: metaData) { (metadata, error) in
if error == nil{
storageRef.downloadURL(completion: { (url, error) in
completion(url)
})
}else{
print("error in save image")
completion(nil)
}
}
}
func saveImage(userName:String, profileImageURL: URL , completion: #escaping ((_ url: URL?) -> ())){
let dict = ["name": "Yogesh", "text": txtText.text!, "profileImageURL": profileImageURL.absoluteString] as [String : Any]
self.ref.child("chat").childByAutoId().setValue(dict)
}
}
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate{
func setupImagePicker(){
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){
imagePicker.sourceType = .savedPhotosAlbum
imagePicker.delegate = self
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
myImageView.image = image
picker.dismiss(animated: true, completion: nil)
}
}