Upload an image from device to firebase - swift

I have been trying to use the code that Firebase documents provide and this is how much I have developed it. It just doesn't work. I have tried putting Storage.storage().reference() but it brings in more error to my code.
let downloadURL: String!
if let imageData = selectedImage.jpegData(compressionQuality: 0.2){
let imgUid = NSUUID().uuidString
let uploadTask = storage.reference().putData(imageData, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
return
}
downloadURL = metadata.downloadURL
The error I receive is use of unidentified resolver storage. But when I try Storage.storage().reference() it brings in 10 different error throughout my code.

Well, I don't know whats going on but, this works for me,
Make sure your pods has at least these in there.
PODFILE
pod 'Firebase/Storage'
pod 'Firebase/Auth' #Auth isn't needed but, you should really use it.
View controller
import UIKit
import FirebaseStorage
class TestView: UIViewController {
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView()
}
#IBAction func uploadPicture(_ sender: Any) {
self.imageView.image = #imageLiteral(resourceName: "playlist.png")
uploadMedia() { url in
guard let url = url else { return }
print(url)
}
}
func uploadMedia(completion: #escaping (_ url: String?) -> Void) {
let storageRef = Storage.storage().reference().child("something.png")
if let uploadData = self.imageView.image?.pngData(){ //You can change this to jpeg, etc
storageRef.putData(uploadData, metadata: nil) { (metadata, error) in
if error != nil {
print("error")
completion(nil)
} else {
storageRef.downloadURL(completion: { (url, error) in
print(url?.absoluteString)
completion(url?.absoluteString)
})
}
}}}
}

Related

Download pdf file from Firebase Storage

I'm trying to link a button from storyboard to my viewcontroller code which supposed to get or download a file from Firebase Storage which is already linked to my app. but no luck.
ViewController first code
#IBAction func downloadButtonPressed(_ sender: Any) {
let userID = Auth.auth().currentUser?.uid
guard let url = URL(string: "https://console.firebase.google.com/project/rent-to-own-93ff1/storage/rent-to-own-93ff1.appspot.com/files/users/userinformation/\(userID!)/folder/Document1.pdf") else { return }
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
let downloadTask = urlSession.downloadTask(with: url)
downloadTask.resume()
}
second code
#IBAction func downloadButtonPressed(_ sender: Any) {
let userID = Auth.auth().currentUser?.uid
let storageRef = Storage.storage().reference().child("users").child("userinformation").child(userID!).child("folder/Document1.pdf");
storageRef.downloadURL { (URL, error) -> Void in
if (error != nil) {
// Handle any errors
} else {
// Get the download URL for 'images/stars.jpg'
}
}
}
Firebase Storage
none of the codes are working for me even after following firebase steps from their website.
Also after pressing download button, the conosole shows the following
022-06-07 22:15:32.241908+0200 Rent To Own Namibia[38234:1806546] GTMSessionFetcher invoking fetch callbacks, data {length = 665, bytes = 0x7b0a2020 226b696e 64223a20 22696465 ... 7d0a2020 5d0a7d0a }, error (null)

Cache Image swift

I try cache An image from An URL from my firebase storage. if I Print my url in function "downloadImage" I can see that I get image URL. But I Print my url in my function getImage, then nothing display.
Here I my Image Service:
import Foundation
import UIKit
import Firebase
class ImageService {
static let cache = NSCache<NSString, UIImage>()
static let storage = Storage.storage()
static let db = Firestore.firestore()
// Downloading image with URL
static func downloadImage(withURL url:URL, completion: #escaping (_ image:UIImage?, _ url:URL)->()) {
let dataTask = URLSession.shared.dataTask(with: url) { data, responseURL, error in
var downloadedImage:UIImage?
if let data = data {
downloadedImage = UIImage(data: data)
}
if downloadedImage != nil {
cache.setObject(downloadedImage!, forKey: url.absoluteString as NSString)
}
DispatchQueue.main.async {
completion(downloadedImage, url)
}
}
dataTask.resume()
}
// Get the downloaded image
static func getImage(withURL url:URL?, completion: #escaping (_ image:UIImage?, _ url:URL)->()) {
if let _url = url {
if let image = cache.object(forKey: _url.absoluteString as NSString) {
completion(image, _url)
print("HEJSAN\(String(describing: url))")
} else {
downloadImage(withURL: _url, completion: completion)
}
}
}
// Set the retrieved image for the UIImageView
static func setImage(imageView image: UIImageView, imageURL url: String) {
getImage(withURL: URL(string: url)) { retrievedImage, error in
image.image = retrievedImage
}
}
This how I try display it in my VC:
override func viewDidLoad() {
super.viewDidLoad()
ImageService.setImage(imageView: logoImage, imageURL: "https://firebasestorage.googleapis.com/v0/b/shutappios.appspot.com/o/LogoImage%2FShutAppLogo.jpg?alt=media&token=13216931-418f-486a-9702-2985b262ab08")
}
I'm not sure if understood well your question but based on what you said it is normal that the getImage when it is called the first time that will execute downloadImage because there will be no image in the cache yet but it will have an image the second time called. maybe the issue here is that you are trying to get the image from the cache before the downloadImage completed because its code is happening on the background async does mean if you are trying to get the cash after that straightaway without waiting. More likely it will not be ready so if you want to make sure that is not going to happen I think you need to add completion to your setImage func something like this:
static func setImage(
imageView image: UIImageView,
imageURL url: String,
completion: (() -> ())? = nil) {
getImage(withURL: URL(string: url)) { retrievedImage, error in
image.image = retrievedImage
completion?()
}
}
this example it will print your log from the getImage as expected the first time is downloading the second is getting from the cache.
ImageService.setImage(imageView: imageView, imageURL: imageURL) {
ImageService.setImage(imageView: self.imageView, imageURL: imageURL)
}
Please note this just an example to give you idea about what could be the issue behind this I hope it will help you!

How to use a stored url from Firebase Database as an image in an UIImageView

I'm new to coding and trying to build an iOS App. I am storing images uploaded by users into my firebase storage and then saving the URL as a string ("https//.....). I am able to get a snapshot to show up in project terminal after I use print(snapshot). It prints, snap (profileImageUrl) https://firebasestorage.... How do I use this snapshot to get the ImageView to show the profile picture most recently saved?
import UIKit
import Firebase
import SDWebImage
class EditProfileViewController: UIViewController {
#IBOutlet weak var ProfileImage: UIImageView!
var selectedImage: UIImage?
var ref:DatabaseReference?
var databaseHandle:DatabaseHandle = 0
var postProfileImage = [String]()
let dbref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
self.ref?.child("users").child(Auth.auth().currentUser!.uid).child("profileImageUrl").observe(.value, with: { (snapshot) in
print(snapshot)
})
ProfileImage.layer.borderWidth = 3.0
ProfileImage.layer.masksToBounds = false
ProfileImage.layer.borderColor = UIColor.white.cgColor
ProfileImage.layer.cornerRadius = ProfileImage.frame.size.width / 2
ProfileImage.clipsToBounds = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(EditProfileViewController.handleSelectProfileImageView))
ProfileImage.addGestureRecognizer(tapGesture)
ProfileImage.isUserInteractionEnabled = true
}
#objc func handleSelectProfileImageView() {
let pickerController = UIImagePickerController()
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
#IBAction func Cancel(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
let user = Auth.auth().currentUser
let fileData = NSData()
#IBAction func DoneButton(_ sender: UIBarButtonItem) {
guard let imageSelected = self.ProfileImage.image else {
print ("Avatar is nil")
return
}
var dict: Dictionary<String, Any> = [
"profileImageUrl": "",
]
guard let imageData = imageSelected.jpegData(compressionQuality: 0.4) else {
return
}
let storageRef = Storage.storage().reference(forURL: "(I have my storage url here")
let imageName = NSUUID().uuidString
let storageProfileRef = storageRef.child("Profile_Images").child(Auth.auth().currentUser!.uid).child("\(imageName).png")
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
storageProfileRef.putData(imageData, metadata: metadata, completion:
{ (StorageMetadata, error) in
if (error != nil) {
return
}
storageProfileRef.downloadURL { (url, error) in
if let metaImageUrl = url?.absoluteString {
dict["profileImageUrl"] = metaImageUrl
Database.database().reference().child("users").child(Auth.auth().currentUser!.uid).updateChildValues(dict, withCompletionBlock: {
(error, ref) in
if error == nil {
print("Done")
}
}
)
}
}
})
dismiss(animated: true, completion: nil)
}
}
extension EditProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//print("did Finish Picking Media")
if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerOriginalImage")] as? UIImage{
selectedImage = image
ProfileImage.image = image
}
dismiss(animated: true, completion: nil)
}
}
I could really use some help!
You can add an extension to UIImageView as below:
extension UIImageView {
func load(url: URL, onLoadCompletion: ((_ isImageLoaded: Bool) -> Void)? = nil) {
self.image = nil
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
onLoadCompletion?(true)
}
} else {
onLoadCompletion?(false)
}
} else {
onLoadCompletion?(false)
}
}
}
}
Assuming your image view outlet is something like this:
#IBOutlet weak var imageView: UIImageView!
Below is the usage when adding a loader:
if let url = URL(string: "https://firebase-storage-url") {
// show a loader here if needed
imageView.load(url: url) { (imageLoaded) in
if imageLoaded {
// hide loader
} else {
// show a place holder image
// hide loader
}
}
} else {
// show a default image
}
Below is the usage without any extra work and just loading the image:
if let url = URL(string: "https://firebase-storage-url") {
imageView.load(url: url)
}

Firebase Upload URL to real time database

I'm trying to upload image url from Firebase Storage to Realtime database.
Here's the code
#IBOutlet weak var jobTitle: UITextField!
#IBOutlet weak var companyName: UITextField!
#IBOutlet weak var jobLocation: UITextField!
#IBOutlet weak var ImageView1stPoster: UIImageView!
var imageUploaded = Data()
var URLtoRealtime = ""
func addPost() {
ref.child("Poster").childByAutoId().setValue(["jobName": jobTitle.text as Any,
"companyTitle": companyName.text as Any,
"jobLocation": jobLocation.text as Any,
"firstPoster": URLtoRealtime as Any,
/*,
"timeStamp":[".sv":"timestamp"]*/]
as[String:Any])
}
// DoneButton to submit everthing :)
#IBAction func DoneButton(_ sender: Any) {
uploadImageToFirebase(imageData: imageUploaded)
createAlert(title: "Post has been submitted", message: "Going to home page")
addPost()
}
func uploadImageToFirebase(imageData: Data) {
// References and vars
let StorageRefrenece = Storage.storage().reference()
let currentUser = Auth.auth().currentUser
let posterImageRef = StorageRefrenece.child("posters").child(currentUser!.uid).child("posterOne.jpg")
let uploadMetaData = StorageMetadata()
uploadMetaData.contentType = "image/jpeg"
// putData to put data to the server using MetaData to orignize everthing.
posterImageRef.putData(imageData, metadata: uploadMetaData) { (uploadedImageMeta, error) in
if error != nil {
print("Error Took place \(String(describing: error?.localizedDescription))")
return
} else {
print("metaData of uploaded image \(uploadMetaData)")
}
}
posterImageRef.downloadURL { (url, error) in
if (error != nil) {
// Handle any errors
print(error!.localizedDescription)
print("NOOOPPPEEE")
} else {
// Get the download URL for 'images/stars.jpg'
print("Working Good")
let UrlString = url!.absoluteString
print(UrlString)
self.URLtoRealtime = UrlString
}
}
}
I'm trying like to make URLString = URLtoRealtime data and then
add the post to firebase.
but what is happening is that it executes addPost() function before
self.URLtoRealtime = UrlString
I don't know how to make the program to execute the previous line of code before addpost() function.
When the done button is touched, you're asynchronously uploading the image to firebase and downloading the URL. However, as you've pointed out, by the time you addPost, the URL hasn't been downloaded yet – you want to do one after the other.
#IBAction func DoneButton(_ sender: Any) {
uploadImageToFirebase(imageData: imageUploaded) { [weak self] (url, error) in
if let url = url {
createAlert(title: "Post has been submitted", message: "Going to home page")
self?.URLtoRealtime = url.absoluteString
self?.addPost()
} else {
self?.createAlert(title: "Post could not be submitted", message: "Try again")
}
}
}
We can add a completion argument to the upload method so that you can addPost once the upload and download of the URL is finished.
func uploadImageToFirebase(imageData: Data, completion: #escaping (URL?, Error?) -> ()) {
guard let uid = Auth.auth().currentUser?.uid else { return completion(nil, nil) }
let posterImageRef = Storage.storage().reference(withChild: "posters/\(uid)/posterOne.jpg")
let uploadMetaData = StorageMetadata(dictionary: [ "contentType": "image/jpeg" ])
posterImageRef.putData(imageData, metadata: uploadMetaData) { (metadata, error) in
if let ref = metadata?.storageReference {
ref.downloadURL(completion: { (url, error) in
completion(url, error)
})
} else {
completion(nil, error)
}
}
}

Image loading lag in tableview with RSS feed datasource in Swift

I am using dispatch_async to download the images from an rss feed to avoid lagging but when I scroll fast, I can see the images are changing, which is pretty annoying. How can I avoid that?
Here is my code:
let backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
dispatch_async(backgroundQueue, {
let url = NSURL(string: fImage)
let data = NSData(contentsOfURL: url!)
dispatch_async(dispatch_get_main_queue(), {
if data != nil {
self.thumbnailIMG.image = UIImage(data: data!)!
} else {
self.thumbnailIMG.image = UIImage(named: "logo_new2")!
}
})
})
Try it this way :
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var thumbnailIMG: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.thumbnailIMG.image = UIImage(named: "logo_new2")
if let checkedUrl = NSURL(string: "http://staging.api.cheapeat.com.au/restaurants/1/photo") {
downloadImage(checkedUrl)
}
}
func downloadImage(url:NSURL){
getDataFromUrl(url) { data in
dispatch_async(dispatch_get_main_queue()) {
self.thumbnailIMG.image = UIImage(data: data!)
}
}
}
func getDataFromUrl(urL:NSURL, completion: ((data: NSData?) -> Void)) {
NSURLSession.sharedSession().dataTaskWithURL(urL) { (data, response, error) in
completion(data: NSData(data: data))
}.resume()
}
}
This is not lagging for me.
May be this will help you too.