I created the below function to fetch image from firebase storage:
func downloadImageFromFirebase(_ imageNameOnFireBase: String, imageViewToBeFilled: UIImageView) {
let storage = Storage.storage()
let reference: StorageReference = storage.reference().child(imageNameOnFireBase)
reference.downloadURL { url , error in
if error != nil {
print(error!.localizedDescription)
imageViewToBeFilled.image = UIImage(named: "default")
} else {
if let url = url {
do {
let data = try Data.init(contentsOf: url)
imageViewToBeFilled.image = UIImage(data: data)
} catch {
print("Error fetching URL")
imageViewToBeFilled.image = UIImage(named: "default")
}
}
}
}
}
When using the function many times it causes loading delay , How can i approach faster and more reliable way of downloading the images ?
You should be able to fetch images from Firebase with URLs, and using SDWebImage it will enable your app to have very fast loading and scrolling times as the images are only loaded once. An excellent tutorial for this can be found here: https://www.youtube.com/watch?v=XPAaxF0rQy0
(He teaches it with Firebase Storage)
Related
This question already has answers here:
Loading/Downloading image from URL on Swift
(39 answers)
Closed 6 months ago.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageOfDog: UIImageView!
struct dataForLoading: Codable {
let message: String
}
override func viewDidLoad() {
super.viewDidLoad()
// load url
let url = "https://dog.ceo/api/breeds/image/random"
guard let loadUrl = URL(string: url) else { return }
// use loaded url in urlSession
URLSession.shared.dataTask(with: loadUrl) {(data, response, error) in
if error != nil{
print("if error printed")
print(error!.localizedDescription)
}
// decode
guard let data = data else { return }
do {
let jsonData = try JSONDecoder().decode(dataForLoading.self, from: data)
DispatchQueue.main.async {
self.imageOfDog.image = UIImage(named: jsonData.message)
}
}
catch let jsonError {
print(jsonError)
}
}.resume()
}
}
i am currentlt using. https://dog.ceo/api/breeds/image/random. this api
for loading random image
i am new to loading Api i am trying to load API through URLSession
when i run project i get below error
Random dog image[5960:196973] [framework] CUIThemeStore: No theme registered with id=0
i think i am not able to decode it properly how can i load image through API
At First Api Generates an url from image like these. {"message":"https://images.dog.ceo/breeds/elkhound-norwegian/n02091467_5985.jpg","status":"success"}
so my idea is to get first API and in Api whaterver url is coming pass it to imageview
The error occurs cause of UIImage(named: jsonData.message) . You can call this only if the image is exist in Assets Folder. You have to use UIImage(data: data)
Example of usage
if let imageURL = URL(string: jsonData.message){
if let data = try? Data(contentsOf: imageURL){
self.imageOfDog.image = UIImage(data: data)
}
}
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"))
}
}
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.
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
}
}
I'm building app and I need to populate a TableView with some users infos, like username and the profile picture. The following code works for downloading and displaying the image.
if let imageFile = usersArr[indexPath.row]["profileImage"] as? PFFile {
let data = try? imageFile.getData()
cell?.imageView?.image = UIImage(data: data!)
}
But this is synchronously and I want it to be asynchronously. So I tried this.
if let imageFile = usersArr[indexPath.row]["profileImage"] as? PFFile {
imageFile.getDataInBackgroundWithBlock({ (data, error) -> Void in
if let imageData = data where error == nil {
cell?.imageView!.image = UIImage(data: imageData)
} else {
cell?.imageView!.image = UIImage(named: "defaultProfile")
}
})
}
But it's not working and I can't figure out why. Not even the defaultProfile image is appearing.
Any tips?
The issue is that the view is not being refreshed once the data has been fetched and image has been set.
I recommend using PFImageView from the ParseUI framework. It is a Parse-made image view which will automatically handle displaying a placeholder while loading, updating the data once available, and refreshing the view once the download is complete. Here's an example usage.
let imageView = PFImageView()
// Set placeholder image
imageView.image = UIImage(named: "placeholder")
// Set remote image
imageView.file = profilePicture
// Once the download completes, the remote image will be displayed
imageView.loadInBackground { (image: UIImage?, error: NSError?) -> Void in
if (error != nil) {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
} else {
println("image loaded")
}
}