Share Post - Storage and DB
Instagram Firebase
Let's now share our post to the entire world out there, even if it's just a few users right now. This step requires uploading our photo to Firebase Storage, retrieving its location URL, and storing it inside of Firebase Database so that it belongs to our user. Before we end our lesson, let's include some bug fixes that will prevent users from uploading too many posts during the upload process.

Comments (29)
magic6435
6 years ago
Dope video! I bought the series just to see what you would do around these areas. The one thing I'm confused about with the Firebase docs is "However, when you fetch data at a location in your database, you also retrieve all of its child nodes.". So does that mean in your posts object if you had 20 users each with 10 images and you tried to list just Brian's node, would it still do the work to retrieve all the other users since they are children of posts? Or since you specify only the Brian will it skip the other users?
Brian Voong
6 years ago
khalid.usa2017@gmail.com
6 years ago
Hi Brian Thank you for your perfect lessons. I'm totally satisfied with the things I have learned from this course. I just would love it if you can please explain the functions of the database storage, like what they do and how to use them. Thank you
Brian Voong
6 years ago
Michael Li
6 years ago
Hi Brain, Love your videos! Really learn a lot from them. And I'm trying to give up on storyboard as you suggested, so far so good, lol. One question: if I want to upload multiple image urls in one post, how should I organize my database tree? Maybe multiple child references under imageUrls? Something like: posts imageUrls image0 image1 image2 ...... caption creationDate ...... What's the best way of doing this? Thank you!
Brian Voong
6 years ago
Michael Li
6 years ago
Thanks Brian
omari
6 years ago
Hey Brian, In the Instagram app you can share posts without having a caption text so why did you decide forcing the user to enter a caption text . Besides that If the user clicks the share button without having a caption text nothing will happen. When he enters a caption text the system allows him to share the post. The user has to be informed in a pretty way that he need to enter a caption text. Maybe an alert or a placeholder text.
Brian Voong
6 years ago
Luis Machado
6 years ago
Hello Brian, Almost at the end of the lesson, when you dismiss the VC (self.dismiss...) it seems to dismiss both VCs, the image picker and the share controller. So, I'm guessing it dismisses all the viewcontrollers that are "part" of the current navigation controller. Is this correct? Furthermore, if, by any chance, I only wanted to dismiss the current viewcontroller, a navController pop would suffice? Thanks and keep up the awesome work ;)
Brian Voong
6 years ago
omari
6 years ago
Hey Brian, in which video I find the how to implement the progress bar when we upload information to firebase that you mentioned at the end of this video ?
Brian Voong
6 years ago
Madhusudhan Ramanujam
6 years ago
Hey brian! If i wanted to store some of the recents posts in a local DB. How would you recommend i proceed ?
Madhusudhan Ramanujam
6 years ago
I wanted to do this because the app will crash if i try to open it up when i dont have an internet connection
Brian Voong
6 years ago
Madhusudhan Ramanujam
6 years ago
Oh okay. I have one more query. I followed your firebase chat app course and completed it. Some apps like whatsapp and so on maintain a local DB after retrieving from their servers. I want to do something similar. I want to store all the retrieved contents from firebase locally in a DB. How would you recommend i proceed? I looked into SQLlite but i didnt find much resources for swift.
Brian Voong
6 years ago
Adam El-Kadi
5 years ago
I have something that will help you. https://www.youtube.com/watch?v=wDZmz9IsB-8 Check it out. This is a pod that helps you check if the user is connected via Data, wifi, or no internet and based on that you can react. I love this video am using it in many of my projects.
mcolonnajr
6 years ago
I love your videos... I'm sure you know the Firebase SwiftKeychainWrapper... I was wondering why haven't you used this in this tutorial to check if the user is already logged in and dismiss the entire login process?
smiller193
6 years ago
Is anyone having an issue with the input accessory view getting stuck at the bottom? When exiting comment screen
Dan Boyle
6 years ago
Can't quite figure out something I'm sure it staring me in the face. When I dismiss the SharePhotoController or the PhotoSelectorController... I'm left staring at my plusController which has a white background and nothing else. Any ideas?
Adam El-Kadi
5 years ago
Great as always. I love the guard let statements instead of the ! operator I am starting to implement that into my code so I get less crashes.
Adam El-Kadi
5 years ago
Hey, Brian I FOUND OUT what the problem was, you know how I told you that the posts were showing up twice in the news feed. Turns out the code is uploading both the 300x300 and the 600x600 images to the database. Thats why you get the post twice. The Database is looking for posts and then its syncs all the photos.
Adam El-Kadi
5 years ago
I am currently looking at a fix.
Adam El-Kadi
5 years ago
Here is the funny thing that I can't get around is that, in the storage the same picture is showing up twice one 300x300 and one 600x600 but in the database under posts it only shows one picture URL.
albaqawi
5 years ago
He Brain and community, I am facing a very strange problem with this project. I am uploading everything correctly as per the code-a-long with Brain to the Storage and RealTime Database. The problem: The entry creation in the realtime Database under the user uuid takes a long time to show up in the Firebase Dashboard. (it is automatically logged / shows up in the Firebase Storage). It can take up to 15 - 30 min wait to show up in the Database viewer). I really do not think it is the iOS code in any way but what settings on Firebase do I have to check?or in the google services .plist file? the user experience is very bad do to this high latency. please help.
Adam El-Kadi
5 years ago
Did you refresh the page (firebase page). Or another thing you can try is if you press on the storage and then press again on the databse section and see if it refreshes.
albaqawi
5 years ago
hi Adam, Yes many times in all different combos, but refresh dose not help at all... I just uploaded an image now (Post) and it took 5 mins to show up as a node in real time database. I cannot find any reported problem like this anywhere, I love any help or if anyone seen this problem/bug before?
albaqawi
5 years ago
hi Adam, Yes many times in all different combos, but refresh dose not help at all... I just uploaded an image now (Post) and it took 5 mins to show up as a node in real time database. I cannot find any reported problem like this anywhere, I love any help or if anyone seen this problem/bug before?
Adam El-Kadi
5 years ago
I’ll look into for you, I’ll see if I can find something.
albaqawi
5 years ago
thank you in advance Adam, I really appreciate it
albaqawi
5 years ago
hi Adam, do not search more I found the problem... In the SharePhotoController.swift, inside the saveToDatabaseWithImageUrl(imageUrl: String) function.... In typing the auto complete picked up a different function making the the Firebase call ref.updateChildValues to be ref.onDisconnectUpdateChildValues man this function was wrong but so impressive, we can use it to update record even after a long time, once user is out of app! learned a new thing from this problem. now all code working instantly on realtime Database :D
Adam El-Kadi
5 years ago
I’m glad you were able to solve the problem. I was trying to recreate the problem with no success sorry
albaqawi
5 years ago
I highly value all your help man! all the best to you too :) remember that function I used by mistake has some very strong and powerful feature it will track that record up to your disconnect to Firebase and do the record update.
albaqawi
5 years ago
I highly value all your help man! all the best to you too :) remember that function I used by mistake has some very strong and powerful feature it will track that record up to your disconnect to Firebase and do the record update.
Adam El-Kadi
5 years ago
Yeah I see
Sanket Ray
5 years ago
For some reason "selectedImage" is nil for me...I had to use "imageView.image" to make it work...Could you please explain why this is happening?
wealthnut79
5 years ago
Hello Brian I have a question concerning how we are setting up our database. How can I setup the Database so that instead of the USERS and POSTS sections first displaying the actual UID of the user it can display the username. 1. Right now we have to click into the UID to find out who the user actually is 2. Is it possible to just have the USERS category with all the users activity inside ie. Posts/Captions instead of having 2 separate categories (users and posts) I hope i was clear with these questions thanks
atran
5 years ago
This is not recommended by Firebase as when you query the list of users' name, you will pull all these posts and captions data as well. So it's best to separate the posts out of users. You can read up more on this on the Firebase documentation: https://firebase.google.com/docs/database/ios/structure-data
Umberto Grimaldi
5 years ago
Hi Brian, I have a problem regarding childByAutoId() that is not appearing maybe because deprecated. How can I solve it? Thanks for all. =)
Umberto Grimaldi
5 years ago
I solved it. Thanks a lot!
omarubilla
3 years ago
Hi Umberto how did you solve this?
Jaylon22
5 years ago
Hi Brian, i've ranned into a small problem, i was trying to get my code to upload post to firebase with speed like yours. But the metadata.downloadUrl method is deprecated. I was resulted into uploading post in equivalent to the method of signing users in just using a post reference. This makes the posting to database extremely slow, and i tried to change my code but now it doesn't post at all, any tips on how i could fix that. Here is my code @objc func handleShare(){ guard let caption = textView.text, caption.characters.count > 0 else {return} guard let image = selectedImage else {return} self.navigationItem.rightBarButtonItem?.isEnabled = false guard let uploadData = UIImageJPEGRepresentation(image, 0.5) else {return} let filename = NSUUID().uuidString let storageRef = Storage.storage().reference() storageRef.child("posts").child(filename).putData(uploadData, metadata: nil) { (metadata, err) in storageRef.downloadURL(completion: {(url, err) in if let err = err{ print("Unable to retrieve URL due to error: \(err.localizedDescription)") self.navigationItem.rightBarButtonItem?.isEnabled = true return } guard let imageUrl = url?.absoluteString else {return} self.saveToDatabaseWithImageUrl(imageUrl: imageUrl) print("Successfully uploaded post to: ", imageUrl) } )} } fileprivate func saveToDatabaseWithImageUrl(imageUrl: String) { guard let postImage = selectedImage else { return } guard let caption = textView.text else { return } guard let uid = Auth.auth().currentUser?.uid else { return } let userPostRef = Database.database().reference().child("posts").child(uid) let ref = userPostRef.childByAutoId() let values = ["imageUrl": imageUrl, "caption": caption, "imageWidth": postImage.size.width, "imageHeight": postImage.size.height, "creationDate": Date().timeIntervalSince1970] as [String : Any] ref.updateChildValues(values) { (err, ref) in if let err = err { self.navigationItem.rightBarButtonItem?.isEnabled = true print("Failed to save post to DB", err) return } print("Successfully saved post to DB") self.dismiss(animated: true, completion: nil) } }
Brian Voong
5 years ago
Jaylon22
5 years ago
Yes sir, will do thank you.
Jaylon22
5 years ago
Brian, i want to say i truly appreciate this course and want to let you know that i am grateful that God sent me to this tutorial. You have been a very great benefit to me making my own app!!!
Brian Voong
5 years ago
Jaylon22
5 years ago
Yes sir it has once again thank you.
Jaylon22
5 years ago
Hey, brian I don't mean to bother you but i have one more small request if i want to make it optional to post a picture or not how could i do that. Because the code we have no is a guard statement to make sure you post a picture. Do you have ideas on how we can make the picture optional and still be able to post(rightbarButton enabled)
Brian Voong
5 years ago
rickkettner
5 years ago
Here is a handy little trick to remove unwanted white space or blank lines that someone might accidentally add to a post's caption... I just modified the existing guard statement for "textView" in the saveToDatabaseWithImageUrl function. guard let postText = textView.text?.trimmingCharacters(in: .whitespacesAndNewlines) else { return }
rickkettner
5 years ago
Here how to ensure the uploaded data gets saved as an "image/jpeg"... which means it can be previewed directly in the browser instead of having to download to test the storage URL. Found it on Stack Overflow. https://stackoverflow.com/a/50612978/9671693 Just involves adding metadata into the ".putData()" method that is already being used.
Brian Voong
5 years ago
hudsonpereira
5 years ago
thanks!
Jaylon22
5 years ago
Hey Brian, I love your videos, i just have a quick question could i use this same exact method but instead upload videos in the place of photos could that work?
Brian Voong
5 years ago
Jaylon22
5 years ago
Great thank you! Have a bless day
Jaylon22
5 years ago
Hey brian, Once again i love your videos i just have a quick question about my code and adding a video url to the post so the user can post videos as well. Here is my code @objc func handleShare() { guard let caption = addCaptionTextView.text, !caption.isEmpty else { return } let filename = NSUUID().uuidString let storageRef = Storage.storage().reference().child("posts").child(filename) storageRef.putFile(from: videoUrl!, metadata: nil, completion: { (metadata, err) in if let err = err { self.navigationItem.rightBarButtonItem?.isEnabled = true print("Failed to upload post image:", err) return } storageRef.downloadURL(completion: { (downloadURL, err) in if let err = err { print("Failed to retrieve downloadURL:", err) return } guard let imageUrl = downloadURL?.absoluteString else { return } print("Successfully uploaded post image:", imageUrl) self.saveToDatabaseWithImageUrl(imageUrl: imageUrl) }) }) } let updateFeedNotificationName = NSNotification.Name(rawValue: "UpdateFeed") fileprivate func saveToDatabaseWithImageUrl(imageUrl: String) { guard let caption = addCaptionTextView.text else { return } guard let uid = Auth.auth().currentUser?.uid else { return } let userPostRef = Database.database().reference().child("posts").child(uid) let ref = userPostRef.childByAutoId() let values = ["imageUrl": imageUrl, "videoUrl": videoUrl!, "caption": caption, "creationDate": Date().timeIntervalSince1970] as [String : Any] ref.updateChildValues(values) { (err, ref) in if let err = err { self.navigationItem.rightBarButtonItem?.isEnabled = true print("Failed to save post to DB", err) return } print("Successfully saved post to DB") self.dismiss(animated: true, completion: nil) } } Save to the storage works perfectly, but saving to the database gives me an error message, how could i attach the video url to the post? Do you have any ideas? Thank you and have a bless day.
Brian Voong
5 years ago
shubhamsaurav
5 years ago
Hey Brian, I did exactly right but it was giving me a error which I was saving post into database. The error was "Domain=com.firebase Code=1 "Permission denied". I changed the security rules which will allow all of users to read and write inside of posts node. The changed security is : { "rules": { "users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } }, "posts":{ ".read" : "auth != null", ".write" : "auth != null" } } } Is this the right solution for this problem? BTW my code is now working fine.
ncytimothy
4 years ago
Yes, that is correct.
Lucrecio909
4 years ago
I was not able to write out "imageUrl = downloadURL?.absoluteString" I looked it up online and it says that swift metadata.downloadURL() not recognized anymore and that 'downloadURL()' is deprecated. I do not know what this means, can you please help? This is as far as I've gotten. @objc func handleShare() { guard let image = selectedImage else { return } guard let uploadData = UIImageJPEGRepresentation(image, 0.5) else { return } let filename = NSUUID().uuidString let storageRef = Storage.storage().reference().child("posts").child(filename).putData(uploadData, metadata: nil) { (metadata, err) in if let err = err { print("failed to upload post image:", err) return } guard let imageUrl = metadata?.storageReference?.downloadURL(completion: <#T##(URL?, Error?) -> Void#>) else { return } print("Successfully uploaded post image") self.saveToDatabaseWithImageUrl() } }
Brian Voong
4 years ago
Lucrecio909
4 years ago
Thank you for the help, I downloaded the project and updated the code.
landahoy55
4 years ago
It's also available in metaData.storageRef.downloadURL(...)
BTol Mohammad
4 years ago
Hi Brain, I am trying to post to the image to the database but the code does not work although I am following exactly your code structure.
Brian Voong
4 years ago
BTol Mohammad
4 years ago
No, I actually do not get any error here is what I have for sharing the image. when I click the button I see the print statement but the image is not in Firebase @objc func handlePost() { print("handling post..") guard let image = selectedImage else { return } guard let uploadData = image.jpegData(compressionQuality: 0.5) else { return } navigationItem.rightBarButtonItem?.isEnabled = false let filename = NSUUID().uuidString let storageRef = Storage.storage().reference().child("posts").child(filename) storageRef.putData(uploadData, metadata: nil) { (metadata, err) in if let err = err { self.navigationItem.rightBarButtonItem?.isEnabled = true print("Failed to upload post image:", err) return } storageRef.downloadURL(completion: { (downloadURL, err) in if let err = err { print("Failed to fetch downloadURL:", err) return } guard let imageUrl = downloadURL?.absoluteString else { return } print("Successfully uploaded post image:", imageUrl) self.saveToDatabaseWithImageUrl(imageUrl: imageUrl) }) } } fileprivate func saveToDatabaseWithImageUrl(imageUrl: String) { guard let postImage = selectedImage else { return } guard let caption = textView.text else { return } guard let uid = Auth.auth().currentUser?.uid else { return } let userPostRef = Database.database().reference().child("posts").child(uid) let ref = userPostRef.childByAutoId() let values = ["imageUrl": imageUrl, "caption": caption, "imageWidth": postImage.size.width, "imageHeight": postImage.size.height, "creationDate": Date().timeIntervalSince1970] as [String : Any] ref.updateChildValues(values) { (err, ref) in if let err = err { self.navigationItem.rightBarButtonItem?.isEnabled = true print("Failed to save post to DB", err) return } print("Successfully saved post to DB") self.dismiss(animated: true, completion: nil) } }
Brian Voong
4 years ago
BTol Mohammad
4 years ago
Now I get this error: dyld: Library not loaded: @rpath/libswiftAVFoundation.dylib Referenced from: /var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Waffer Reason: no suitable image found. Did find: /private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib: code signature invalid for '/private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib' /private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib: code signature invalid for '/private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib' /private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib: stat() failed with errno=1 /private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib: code signature invalid for '/private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib' /private/var/containers/Bundle/Application/0CE86395-79E5-4918-949F-E85C40C1A3FE/Waffer.app/Frameworks/libswiftAVFoundation.dylib: stat() failed with errno=1 which is weird because I did not change anything except​ the pod update
BTol Mohammad
4 years ago
Never mind fixed it
Lucrecio909
4 years ago
UIImageJPEGRepresentation has been replaced by instance method Change: let uploadData = UIImageJPEGRepresentation(image, 0.5) to: let uploadData = image.jpegData(compressionQuality: 0.5)
Clint Larenz Nurse
4 years ago
Hi Brain, What do I do if I want users to have the option to upload images in more than one area besides their profile? For example I have a collection view that allows users to select where else they would like to upload their image ( by default if they do not choose it would be the profile) and if they select a cell it'll display that post in another category as well. Do you know how I can go about that?
michvelmccxrd
4 years ago
Hi Brian! First of all, your videos are so informative and while I'm still a beginner, I have a lot more confidence in my abilities because of you. So thank you so much! I seem to be having an issue with my image appearing in the storage. Is this because I am using an IBAction func? @IBAction func handleShareButton(_ sender: Any) { guard let image = selectedImage else { return } guard let uploadData = image.jpegData(compressionQuality: 0.5) else { return } let filename = NSUUID().uuidString let storageRef = Storage.storage().reference().child("posts").child(filename) storageRef.putData(uploadData, metadata: nil) { (metadata, err) in if let err = err { print("Failed to upload post image:", err) return } storageRef.downloadURL(completion: { (downloadURL, err) in if let err = err { print("Failed to fetch downloadURL:", err) return } guard let imageUrl = downloadURL?.absoluteString else { return } print("Successfully uploaded post image:", imageUrl) }) }
Brian Voong
4 years ago
michvelmccxrd
4 years ago
Sorry! I realized what I did wrong. Thanks again!
Patrick Cockrill
4 years ago
Hey Brian, So I’m currently writing a share post UI and it will have multi-image sharing capabilities. I have the base code for key value pairs but my images are in a [UIImage] array. How could I go about saving them into storage? I tried looping through the data structure but that just duplicates the save to database.
Brian Voong
4 years ago
Patrick Cockrill
4 years ago
Using dispatchGroup is used for loading collectionViews is it not? This currently just saves the 0th index of images = [UIImage]. @objc func handleShare() { guard let title = itemTitle.text, !title.isEmpty else { return } guard let price = priceTitle.text, !price.isEmpty else { return } guard let category = categoryTitle.text, !category.isEmpty else { return } navigationItem.rightBarButtonItem?.isEnabled = false navigationController?.toolbar.isUserInteractionEnabled = false let image = images[0] guard let uploadData = image.jpegData(compressionQuality: 0.3) else { return } let filename = NSUUID().uuidString let storageRef = Storage.storage().reference().child("posts").child(filename) storageRef.putData(uploadData, metadata: nil) { (metadata, error) in if let err = error { print("Failed to upload image to Storage:", err) return } storageRef.downloadURL(completion: { (downloadURL, error) in if let err = error { print("Failed to retrieve downloaded url:", err) return } guard let imageUrl = downloadURL?.absoluteString else { return } print("Successfully uploaded post images:", imageUrl) // Call helper function of saving to databse (title, price, description, etc..) self.saveItemDetailsToDatabaseWithUrl(imageUrl: imageUrl) }) } }
Patrick Cockrill
4 years ago
Could you save the image when you append it in the 'didFinishPickingWithOptions' or would that lead to the same problem of all the extra calls.
Brian Voong
4 years ago
Patrick Cockrill
4 years ago
Yeah I'm just thinking in terms of where you'd 'enter' and where you'd 'leave' because I think (please correct me if I'm wrong) you'd enter right before the Storage.storage().ref() call, and leave right before the self.saveItemDetailsToDB()? then you'd have to change the saveItemDetails to take in an array right?
Clint Larenz Nurse
3 years ago
Hey Brain, does these lessons cover how to change thew height of the post based on the crop? If I crop it to where the photo is longer, it still comes out to the same size of about 375
didar490
3 years ago
Hi Brian, I am getting an issue of this: 2020-03-04 20:07:10.373247-0800 InstagramFirebase[67748:8739205] [core] "Error returned from daemon: Error Domain=com.apple.accounts Code=7 "(null)"" Optional(<UIImage:0x600000542e20 anonymous {200, 132}>) 2020-03-04 20:07:11.490818-0800 InstagramFirebase[67748:8739205] [UICollectionView] Warning: Invalid IndexPath <NSIndexPath: 0xf6d2a97c51a2b2f9> {length = 2, path = 2 - 0} specified - will use a contentOffset of {0,0} as a fallback value. <UICollectionView: 0x7fb84202fe00; frame = (0 0; 414 842); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x6000039c3cc0>; layer = <CALayer: 0x600003724e60>; contentOffset: {0, -56}; contentSize: {414, 725.25}; adjustedContentInset: {56, 0, 34, 0}; layout: <UICollectionViewFlowLayout: 0x7fb84151d2b0>; dataSource: <InstagramFirebase.PhotoSelectorController: 0x7fb841522e20>> HOW TO SOLVE IT?
didar490
3 years ago
I updated the Xcode to the latest version, I am assuming that the error coming from PhotoSelectorController, but everything worked fine till the update
HELP & SUPPORT