How to share image downloaded from firebase storage between different views? - ios

This is the code i use to fetch the image from the storage. It works like charm but i dont want to redownload it on different views again.
func retreiveImagesFromFireBase(downloadUrl:String,imageHolder:UIImageView){
if downloadUrl != "" {
let storageRef = Storage.storage().reference(forURL: downloadUrl)
// Download the data, assuming a max size of 1MB (you can change this as necessary)
storageRef.getData(maxSize: 5*1024*1024) { (data, error) in
if error == nil {
if let pic = UIImage(data: data!) {
imageHolder.image = pic
}
} else {
print(error)
}
}
}
}
How should i handle this?

If you have only one or two images then simply store in userdefault and then you can access in any viewController, Store image as data in userdefault
whenever you want to use just convert data to image and use it, See the following code to convert data to image
let image = UIImage(data: imageData)

Just declare UIImage globally in your class, and inside your function, where you are setting imageHolder, assign that downloaded image to global image, and use it where ever you want.
UIImage image;
func retreiveImagesFromFireBase(downloadUrl:String,imageHolder:UIImageView){
if downloadUrl != ""{
let storageRef = Storage.storage().reference(forURL: downloadUrl)
// Download the data, assuming a max size of 1MB (you can change this as necessary)
storageRef.getData(maxSize: 5*1024*1024) { (data, error) in
if error == nil{
if let pic = UIImage(data: data!){
imageHolder.image = pic
image = pic // use it on other views
}
}else{
print(error)
}
}
}
}

You can do
class Service {
static let shared = Service()
var image1:UIImage?
var image2:UIImage?
let imageLink = "//////" // or with SDWebImage
}
if let pic = UIImage(data: data!){
Service.shared.image = pic
}
Or use SDWebImage and share the link , you can aslo make a global var like
var image:UIImage?
but it's not recommended as it has no grouping to let the developer know it's source local/instance/global so it's confusing unlike singleton

Related

Display Image downloaded from downloadURL generated by Firebase

I need to display the images that have been stored on the storage on Firebase. Right now, I only tracked the images using the link generated by function downloadURL:
func UploadImage(imageData: Data, path: String, completion: #escaping (String) -> ()){
let storage = Storage.storage().reference()
let uid = Auth.auth().currentUser?.uid
storage.child(path).child(uid ?? "").putData(imageData, metadata: nil) { (_, err) in
if err != nil{
completion("")
return
}
// Downloading Url And Sending Back...
storage.child(path).child(uid ?? "").downloadURL { (url, err) in
if err != nil{
completion("")
return
}
completion("\(url!)")
}
}
}
So all I can get is a hyperlink that is like: https://firebasestorage.googleapis.com/v0/b/getting-started-20f2f.appspot.com/o/profile_Photos%2FGQ1KR9H1mLZl2NAw9KQcRe7d72N2?alt=media&token=473ce86c-52ba-42ec-be71-32cc7dc895d7.
I refer to the official documentation, it seems that only when I have the name of the image file can I download it to an ImageView or UIImageView object. However, the link does not make any sense to me, so what can I do?
EDIT
I actually tried a solution provided by the official documentation:
func imageDownloader(_ imageURL: String) {
let store = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let imageRef = store.child(imageURL)
var myImageView = UIImageView()
imageRef.getData(completion: { (error, data) in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Data for "images/island.jpg" is returned
let image = UIImage(data: data!)
}
})
}
But it suggests that I need to change something because Cannot convert value of type 'DataSnapshot' to expected argument type 'Data'.
If you're storing the image paths in Firestore, actually the exact file name does not matter if there is only one file available under the fork. So you just need to specify the path.
To then download the image from Storage, construct the path and download:
let uid = Auth.auth().currentUser?.uid
Storage.storage().reference().child("the\path\to\your\uid\collection").child(uid).getData(maxSize: 1048576, completion: { (data, error) in
if let data = data,
let img = UIImage(data: data) {
// do something with your image
} else {
if let error = error {
print(error)
}
// handle errors
}
})
You are uploading to Storage.storage(), but then in your imageDownloader, you're attempting to use Database.database(), which has a similar-looking API, but is, in fact, different.
Make sure to use Storage.storage() and that the closure parameters are in the order data, error in.
Finally, right now in your imageDownloader, it doesn't look like you're doing anything yet with var myImageView = UIImageView(), but keep in mind that you won't have access to the UIImage until the async getData completes.
Store your images at Firebase Storage & then retrieve using this code.
Storage.storage().reference.child("ProfilePhotos").child("ImageName").downloadURL {(url, _) in
DispatchQueue.main.async {
guard let url = url else { return }
imageView.setImage(with: url, placeholder: UIImage(named: "dummyImage"))
}
}

ImageView to Firebase Storage in Swift

I am trying to upload an image from ImageView to Firebase storage but it won't work.
I have listed my code below: My image view is called ProfileImage
let storageRef = Storage.storage().reference().child("myImage.png")
if let uploadData = self.ProfileImage.image!.pngData() {
storageRef.putFile(from: uploadData, metadata: nil) { (metadata, error) in
if error != nil {
print("error")
completion(nil)
} else {
// your uploaded photo url.
}
}
}
It comes up with the error "Cannot convert value of type 'Data' to expected argument type 'URL'
You are trying to upload Data, not a file. Replace
putFile
With
putData
And it should work fine
Try this code :-
let storageRef = Storage.storage().reference().child("myImage.png")
if let uploadData = UIImagePNGRepresentation(self.profileImage.image!) {
storageRef.put(uploadData, metadata: nil) { (metadata, error) in
if error != nil {
print("\(error.localizeDescription)")
} else {
// your uploaded photo url.
}
}
let refDatabase = Database.database().reference()
var refstorage = Storage.storage().reference()
let data = image.jpegData(compressionQuality: 1.0) //
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
let postkey = refDatabase.child("Post").childByAutoId().key
print(postkey)
let imagename = "PostImage/\(postkey).png"
refstorage = refstorage.child(imagename)
let timestamp = Date().timeIntervalSince1970 // you can use this to track time when it was uploaded.
self.refstorage?.putData(data!, metadata: metadata, completion: { (meta, error) in
if error == nil{
if let imageData = meta?.downloadURL()?.absoluteString{
// DO SOMETHING
} else {
print("Couldn't get the URL for image")
}
}
})
I know that this question has been answered, but there is an easier way to do this. Along with import Firebase and Firebase Storage, you will also have to add FirebaseUI to your podfile and import it.
After you have done that, you could get your image to your app much simpler.
let storage = Storage.storage()
let storageRef = storage.reference()
let placeholderImage = UIImage(named: "placeholder.jpeg")
let reference = storageRef.child("myImage.png")
ProfileImage.sd_setImage(with: reference, placeholderImage: placholderImage)
(The placeholder Image would just be a transparent image that you put in your assets folder in XCode that you could reuse multiple times in your application, for whenever you needed to get a Firebase Image on your app.)

Firebase Storage Image Not Downloading in Tableview

Firebase Storage Image Not Downloading in Tableview. If I replace the line let tempImageRef = storage.child("myFiles/sample.jpg"), it's showing the single image. But if try to grab all the images inside 'myFiles' , it doesn't work. Please help
func fetchPhotos()
{
//let database = FIRDatabase.database().reference()
let storage = FIRStorage.storage().reference(forURL: "gs://fir-test-bafca.appspot.com")
let tempImageRef = storage.child("myFiles/")
tempImageRef.data(withMaxSize: (1*1024*1024)) { (data, error) in
if error != nil{
print(error!)
}else{
print(data!)
let pic = UIImage(data: data!)
self.picArray.append(pic!)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
You are referencing an entire folder (myFiles/). That wont work. You need to reference each image individually.
One way to do this is to write the image metadata to your realtime database when you upload an image. Then read the metadata (more specifically the path) and then reference the image that way.
If you have 3 images you want to upload and store, you could write the metadata as follows:
/images
/image1key
/metdata
/path
/image2key
/metdata
/path
/image3key
/metdata
/path
Then you can query your database for your images path's like so
let ref = Firebase.database().ref("images")
ref.observe(.value, withCompletion: { snapshot in
if let values = snapshot.value as? [String : Any] {
if let metadata = values["metadata"] as? [String: Any] {
let imagePath = metadata["path"]
//Now download your image from storage.
}
}
})
This isn't the cleanest code and you can definitely improve, but it will work :)

uploading/downloading multiple images the right way?

i'm trying to upload or download images using Nuke(framework for downloading and Caching images) And Firebase to upload images as the backend
for single file it's easy to deal with without any problem
but for multiple ones i don't really know what to do right
i'm having an issues where it don't do it job synchronously
it downloads second image before the first one sometimes
i'll show my way of downloading and uploading multiple images
For download i put the code in for-loop
func downloadImages(completion: (result: [ImageSource]) -> Void){
var images = [ImageSource]()
for i in 0...imageURLs.count-1{
let request = ImageRequest(URL: NSURL(string:imageURLs[i])!)
Nuke.taskWith(request) { response in
if response.isSuccess{
let image = ImageSource(image: response.image!)
images.append(image)
if i == self.imageURLs.count-1 {
completion(result: images)
}
}
}.resume()
}
}
And for uploading where the user chooses the images
form image picker and return it as NSData array
And then perform this code
func uploadImages(completion: (result: [String]) -> Void){
let storageRef = storage.referenceForURL("gs://project-xxxxxxxxx.appspot.com/Uploads/\(ref.childByAutoId())")
var imageUrl = [String]()
var imgNum = 0
for i in 0...imageData.count-1 {
let imagesRef = storageRef.child("\(FIRAuth.auth()?.currentUser?.uid) \(imgNum)")
imgNum+=1
let uploadTask = imagesRef.putData(imageData[i], metadata: nil) { metadata, error in
if (error != nil) {
print("error")
imageUrl = [String]()
completion(result: imageUrl)
} else {
print("uploading")
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL()?.absoluteString
print(downloadURL)
imageUrl.append(downloadURL!)
if i == imageUrl.count-1{ //end of the loop
print("completionUpload")
completion(result: imageUrl)
}
}
}}
this is good way to do this task ?
what should i do to make each image downloads in order ?
please give me anything that may help example code , link etc ..
Thanks in advance
We highly recommend using Firebase Storage and the Firebase Realtime Database together to accomplish lists of downloads:
Shared:
// Firebase services
var database: FIRDatabase!
var storage: FIRStorage!
...
// Initialize Database, Auth, Storage
database = FIRDatabase.database()
storage = FIRStorage.storage()
Upload:
let fileData = NSData() // get data...
let storageRef = storage.reference().child("myFiles/myFile")
storageRef.putData(fileData).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let downloadURL = snapshot.metadata?.downloadURL()?.absoluteString
// Write the download URL to the Realtime Database
let dbRef = database.reference().child("myFiles/myFile")
dbRef.setValue(downloadURL)
}
Download:
let dbRef = database.reference().child("myFiles")
dbRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
// Get download URL from snapshot
let downloadURL = snapshot.value() as! String
// Now use Nuke (or another third party lib)
let request = ImageRequest(URL: NSURL(string:downloadURL)!)
Nuke.taskWith(request) { response in
// Do something with response
}
// Alternatively, you can use the Storage built-ins:
// Create a storage reference from the URL
let storageRef = storage.referenceFromURL(downloadURL)
// Download the data, assuming a max size of 1MB (you can change this as necessary)
storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
// Do something with data...
})
})
For more information, see Zero to App: Develop with Firebase, and it's associated source code, for a practical example of how to do this.

How to download and view images from the new Firebase Storage?

I am able to upload images to Firebase Storage but I am having trouble downloading them. This is my code to download images:
let storage = FIRStorage.storage()
let localURL : NSURL! = NSURL(string: "file:///Documents/co.png")
// i also tried let localURL : NSURL! = NSURL.fileURLWithPath("file:///Documents/co.png")
func download() {
let storageRef = storage.referenceForURL("gs://project-5547819591027666607.appspot.com")
let imageRef = storageRef.child("co.png")
let downloadTask = imageRef.writeToFile(localURL) { (URL, error) -> Void in
if (error != nil) {
print(error?.localizedDescription)
}
else {
self.imageView.image = UIImage(data: data!)
}
}
}
I am receiving - Optional("An unknown error occurred, please check the server response.")
Also once I get them downloaded How would I view that image?
For trying to see if the image was downloaded I created a UIImageView and set an outlet for it in storyboard called "imageView" then set the downloaded image to the UIImageView.
self.imageView.image = UIImage(data: data!)
Try
first getting reference to the image you want to download using
let reference = FIRStorage.storage().reference("uploads/sample.jpg")
If you know the size of image is low - like 1-2 mb max . download the image in memory
reference.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
print(error)
} else {
let myImage: UIImage! = UIImage(data: data!)
}
}
This will be the quickest and easy way to download directly from Firebase Storage.
However there are cases when you want the progress blocks and certain other things like caching. In such cases you could use any third party like Alamofire to download the image from the url you get from Firebase Storage.
To get the url do something like this
reference.downloadURLWithCompletion { (URL, error) -> Void in
if (error != nil) {
// Handle any errors
} else {
print(URL)
// download image using NSURLSession or Alamofire
}
}

Resources