How can I upload an Image to Firebase with different strings? - swift

In this code Im able to successfully post an image to Firebase. But I would like to add some strings along with it.
#objc func Post(){
print("Post Clicked")
let imageName = "\(NSUUID().uuidString).jpeg"
let imagesFolder = Storage.storage().reference().child("Post")
if let image = imageView.image{
if let imageData : Data = image.jpegData(compressionQuality: 1){
imagesFolder.child(imageName).putData(imageData, metadata: nil) { (metaData, error) in
if let error = error{
print(error)
}else{
imagesFolder.child(imageName).downloadURL { (url, error) in
if let imageURL = url?.absoluteString{
self.imageURL = imageURL
print("Success")
}
}
}
}
}
}
}
How can I upload these custom strings from UILabels along with the same image? I have tried placing this code in different areas of the Post function but it does not work. What is the proper way to do this?
//([
//"Title" : titleLabel.text,
//"Article" : articleLabel.text,
//"Author" : authorLabel.text,
//"Date" : DateLabel.text,
//])

Related

Using Firebase Storage for Uploading Images

I can only upload a single photo to FirebaseStorage.
All the tutorials I have seen on youtube use FirebaseStorage to save user's profile pictures. However, I am trying to make a restaurant app where I should be able to keep several pictures and not only one. My code right now only allows me to keep one. As soon as I try to upload a second image, it erases the first one.
Here's my code:
#IBAction func agregarComidaFav(_ sender: Any) {
guard let imageData = imagen?.jpegData(compressionQuality: 0.4) else {
return
}
let storageRef = Storage.storage().reference(forURL: "gs://comidas-68043.appspot.com")
let storageProfileRef = storageRef.child("ComidasFavoritas")
let metadata = StorageMetadata()
metadata.contentType = "image/png"
storageRef.child("comidasFavoritas/png").putData(imageData, metadata: metadata) { (storageMetaData, error) in
if error != nil {
print(error?.localizedDescription ?? "")
return
}
}
storageProfileRef.downloadURL(completion: { (url, error) in
if let metaImageUrl = url?.absoluteString {
print(metaImageUrl)
self.imagenURL = metaImageUrl
}
})
var ref: DocumentReference? = nil
ref = db.collection("comidasFavoritas").addDocument(data: [
"imagenURL" : imagenURL
]) { err in
if let err = err {
print("Error agregando comida: \(err)")
} else {
let id = ref!.documentID
print("Comida agregado con ID: \(id)")
}
}
}
This line:
storageRef.child("comidasFavoritas/png").putData(...)
...guarantees that each time, the data is going to be written to "comidasFavoritas/png"
I don't know anything about how you're keeping track of your data/images in your app, but you'll probably need some way to keep track of an ID for that image. Then, when you store it, you could store it like:
storageRef.child("comidasFavoritas/png\(imageId)").putData(...)
You'd probably also want to store that ID in your database when you store the image URL.

Swift: upload multiple images to Firestore and assign URLs to object

I'm making an app whereby users post 2 images. I'm using Firebase for storage and as my database.
In my method to upload the images what I had wanted to do was to essentially use this method to return the URLs separately as well. I had written the following:
private func uploadImage(image: UIImage) -> URL? {
let randomName = UUID()
let storageRef = storage.reference().child("\(randomName)/png")
guard let uploadData = image.pngData() else { return nil}
var imageUrl: URL?
storageRef.putData(uploadData, metadata: nil) { (metadata, error) in
if error != nil {
print(error?.localizedDescription)
return
}
storageRef.downloadURL { (url, error) in
if error != nil {
print(error?.localizedDescription)
} else {
imageUrl = url
}
}
}
return imageUrl
}
And then I wrote the following 'post' method which is run when the submit button is tapped:
#objc func post() {
if let question = questionText.text,
let hashtagText = hashtagTextField.text,
let userHandle = Auth.auth().currentUser?.email,
let firstImage = left.image,
let secondImage = right.image,
let firstImageURL = uploadImage(image: firstImage)?.absoluteString,
let secondImageURL = uploadImage(image: secondImage)?.absoluteString
{
db.collection("posts").addDocument(data: [
"firstImage" : firstImageURL,
"secondImage" : secondImageURL,
"question" : question,
"hashtagText" : hashtagText,
"userHandle" : userHandle
]) { (error) in
if let e = error {
print("There was an issue saving data to Firestore, \(e)")
} else {
print("Successfully saved data")
self.dismiss(animated: true, completion: nil)
}
}
}
}
However, obviously the first method is not going to work as the closure is run after imageUrl is returned, therefore returning nil.
I've been trying to figure out how to manage this scenario - I had considered using a loop to populate an array of images but this got messy and I'm sure it is not the standard way to handle this. Any help would be greatly appreciated.
The return imageUrl is in the wrong place. It will return before Firebase has had time to store the image and return the url.
Additionally, the name of the file is not going to work. You currently have
storage.reference().child("\(randomName)/png") // xxxxx/png?
when it should be
storage.reference().child("\(randomName).png") // xxxxx.png
You can't 'return' data from a Firebase closure because firebase is asynchronous - a completion handler may possibly be a solution, but we don't know what the total use case is.
Let's assume you want want to store a users vacation picture in storage and then store that url in Firestore
private func uploadImage(image: UIImage) {
guard let uid = Auth.auth().currentUser?.uid else { return } //this users uid
let storageRef = storage.reference().child(uid).child("vacation.png")
//the path will be storage/users uid/vacation.png
guard let uploadData = image.pngData() else { return nil}
storageRef.putData(uploadData, metadata: nil) { (metadata, error) in
if error != nil {
print(error?.localizedDescription)
return
}
storageRef.downloadURL { (url, error) in
if error != nil {
print(error?.localizedDescription)
} else {
if url != nil {
//it's here where we store the imageUrl in Firestore
let dict = ["theUrl": url?.absoluteURL)]
let userRef = self.db.collection("users").document(uid)
//self.db points to *my* Firestore
userRef.collection("my_pics").addDocument(data: dict)
//will store in firstore/users/uid/docId/theUrl: the url
}
}
}
}
}

Got nil when download image link from firebase

I try to upload multiple images from library to Firebase storage. The upload process works perfectly, all the images is on Firebase storage but when i try to download the image url link to save in database, it shows nil. Please help me how to fix this? Thank a lot
for imageData in ArrayMedia {
print(imageData)
let filePath = "\(currentUserId)/\(key)"
let data = UIImageJPEGRepresentation(imageData, 0.3)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
storageReference.child(filePath).putData(data!, metadata: metadata, completion: { (metaData, error) in
print(metadata)
if error != nil {
print(error?.localizedDescription as Any)
} else {
let PhotoUrl = metadata.downloadURL()?.absoluteString // GOT NIL IN THIS LINE
print(PhotoUrl)
let value = ["Username" : currentUserName, "UserId" : currentUserId, "Text" : self.tvPost.text] as [String : Any]
databaseReference.child("PendingPost").child(currentUserId).child(key).updateChildValues(value)
databaseReference.child("PendingPost").child(currentUserId).child(key).child("Images").child(key).setValue(["PhotoUrl": PhotoUrl])
}
self.showAlert()
})
}
Try to use this instead :
storageRef.child(path).putData(data, metadata: metaData){ (metaData,error) in
if let error = error {
print(error.localizedDescription)
return
} else {
let downloadURL = metaData!.downloadURL()!.absoluteString
}
}
It works for me.

uploading images to firebase storage

I am trying to upload two images to firebase storage but it is just uploading one
let imageOne = images[0] as! UIImage
let imageTwo = images[1] as! UIImage
func uploadImage(image: UIImage){
let randomName = randomStringWithLength(length: 5)
let randomNames = randomStringWithLength(length: 9)
let imageData = UIImageJPEGRepresentation(imageOne, 1.0)
let imageDatas = UIImageJPEGRepresentation(imageTwo, 1.0)
let uploadRef = FIRStorage.storage().reference().child("images/\(randomName).jpg")
uploadRef.put(imageData!, metadata: nil) { metadata,
error in
if error == nil {
print("successfully uploaded Image")
AppDelegate.instance().dismissActivityIndicator()
self.imageFileName = "\(randomName as String).jpg"
uploadRef.put(imageDatas!, metadata: nil) { metadata,
error in
if error == nil {
self.imageFileNameTwo = "\(randomNames as String).jpg"
} else{
print("Error uploading image")
}
Only imageOne is uploading. How do I uploading two images at once?
Try like this:
let imageOne = images[0] as! UIImage
let imageTwo = images[1] as! UIImage
func uploadImage(image: UIImage){
let randomName = randomStringWithLength(length: 5)
let randomNames = randomStringWithLength(length: 9)
let imageData = UIImageJPEGRepresentation(imageOne, 1.0)
let imageDatas = UIImageJPEGRepresentation(imageTwo, 1.0)
let uploadRef = FIRStorage.storage().reference().child("images/\(randomName).jpg")
uploadRef.put(imageData!, metadata: nil) { metadata,
error in
if error == nil {
print("successfully uploaded Image")
AppDelegate.instance().dismissActivityIndicator()
self.imageFileName = "\(randomName as String).jpg"
randomName = randomStringWithLength(length: 5)
let uploadRef2 = FIRStorage.storage().reference().child("images/\(randomName).jpg")
uploadRef2.put(imageDatas!, metadata: nil) { metadata,
error in
if error == nil {
self.imageFileNameTwo = "\(randomNames as String).jpg"
} else{
print("Error uploading image")
}
In your code you are uploading 2 images to the one ref.
Hope it helps
I would post as a comment but I don't have enough reputation yet. Why don't you just make the function upload one image as the name suggests, and then call the function twice passing in the first image the first time and then the second image the second time.

Use Facebook profile picture as you profile picture Swift

I am getting facebook's profile picture and displaying it as the profile picture in my app. Here is the code.
if let user = FIRAuth.auth()?.currentUser{
let photoUrl = user.photoURL
let name = user.displayName
self.FacebookUser.text = name
let storage = FIRStorage.storage()
//refer your particular storage service
let storageRef = storage.reference(forURL: "gs://gsignme-14416.appspot.com")
let profilePicRef = storageRef.child(user.uid+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024, completion: { (data, error) -> Void in
if (error == nil){
self.FacebookPic.image = UIImage(data: data!)
}else{
print("Error downloading image:" )
}
})
if(self.FacebookPic.image == nil)
{
var profilePic = FBSDKGraphRequest(graphPath: "me/picture", parameters: ["height": 300, "width": 300, "redirect": false], httpMethod: "GET")
profilePic?.start(completionHandler: {(_ connection, result, error) -> Void in
// Handle the result
if error == nil {
if let dictionary = result as? [String: Any],
let data = dictionary["data"] as? [String:Any],
let urlPic = data["url"] as? String{
if let imageData = NSData(contentsOf: NSURL(string: urlPic)!as URL){
let uploadTask = profilePicRef.put(imageData as Data, metadata: nil) {
metadata, error in
if (error == nil)
{
let downloadurl = metadata!.downloadURL
}
else
{
print("Error in downloading image")
}
}
self.FacebookPic.image = UIImage(data: imageData as Data)
}}}})}
}else{
}
//The END of the Facebook user and picture code
I was able to get it working for a couple days and now it doesn't work anymore, I have gone through it line by line and I honestly can't figure out why it is not working.
I used this code:
func pictureFromFirebase(loginMethod: Int)
{
if loginMethod == 0 //FB
{
var profilePic = FBSDKGraphRequest(graphPath: "me/picture", parameters: ["height":300, "width":300, "redirect":false], httpMethod: "GET")
let profilePicRef = storageRef.child((user?.uid)!+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
// Uh-oh, an error occurred!
// but we don't need to do anything yet. Try to download the profile pic
}
if (data != nil)
{
print("no need to download image from facebook")
self.profileImage.image = UIImage (data: data!)
}
else
{
// THIS IS THE BLOCK THAT HAS BEEN MOVED
// WHICH WILL NOW BE EXECUTED IN TWO CONDITIONS -
// 1. AN ERROR IN THE DOWNLOAD
// 2. NO PROFILE PIC AVAILABLE
print("downloading image from facebook")
profilePic?.start(completionHandler: {(_ connection, _ result, _ error) -> Void in
if (error == nil)
{
if let dictionary = result as? [String:Any], let data = dictionary["data"] as? [String:Any],
let urlPic = data["url"] as? String {
if let imageData = NSData(contentsOf: NSURL(string: urlPic)! as URL)
{
let uploadTask = profilePicRef.put(imageData as Data, metadata: nil){
metadata, error in
if (error == nil)
{
let downloadUrl = metadata!.downloadURL
}
else
{
print("error in downloading image")
}
}
self.profileImage.image = UIImage(data: imageData as Data)
}
}
}
})
}
}
}
}
from this post Second If statement gets called before first statement finished in one function and it worked
you just get your facebook profile pic. using this url and put the url in your UIImageview
let profilepicURl = "https://graph.facebook.com/\(user_id_fb)/picture?type=large" //user_id_fb like 1251246454544 your facebook ID