Retrieving image from Firebase Storage using Swift

29,538

Solution 1

We highly recommend using Firebase Storage and the Firebase Realtime Database together to accomplish this. Here's a full example:

Shared:

// Firebase services
var database: FIRDatabase!
var storage: FIRStorage!
...
// Initialize Database, Auth, Storage
database = FIRDatabase.database()
storage = FIRStorage.storage()
...
// Initialize an array for your pictures
var picArray: [UIImage]()

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
  // 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
    // Create a UIImage, add it to the array
    let pic = UIImage(data: data)
    picArray.append(pic)
  })
})

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.

Solution 2

1. Swift 4.1 Retrive images from Firebase Storage Update RULES for your "STORAGE" left panel firebase option only with your app name:-

service firebase.storage {
  match /b/MyApp-201223.appspot.com/o {
    match /{allPaths=**} {
      // Allow access by all users
      allow read, write;
    }
  }
}

2. Create a Simple method with callbacks in your class where you imported firebase storage:-

      func downloadImages(folderPath:String,success:@escaping (_ image:UIImage)->(),failure:@escaping (_ error:Error)->()){
        for i in 0 ..< 194{
            // Create a reference with an initial file path and name
            let reference = Storage.storage().reference(withPath: "\(folderPath)/0.jpg")
            reference.getData(maxSize: (1 * 1024 * 1024)) { (data, error) in
                if let _error = error{
                    print(_error)
                    failure(_error)
                } else {
                    if let _data  = data {
                        let myImage:UIImage! = UIImage(data: _data)
                        success(myImage)
                    }
                }
            }

        }
     }

3. Use this method wherever you want:-

      self.downloadImages(folderPath: "MyAppImages", success: { (img) in
            print(img)
        }) { (error) in
            print(error)
        }

Solution 3

I highly recommend using the built in FirebaseUI function sd_setImage. It has built in caching features and is way faster than having to use the Data representation from the Storage database.

Be sure to import FirebaseUI and add it to your podfile.

In Swift 4,

let ref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let userRef = ref.child("users").child(uid!)
var myImageView = UIImageView()

userRef.getDocument { (document, error) in
    if let document = document, document.exists {
        let myData = document.data()
        if let profileURL = myData["profileURL"] as? String {
            let storageRef = Storage.storage().reference(forURL: profileURL)
            myImageView.sd_setImage(with: storageRef, placeholderImage: UIImage(named: "placeholder.png"))
        }
        else {
            print("profileURL is nil")
        }
    } 
    else {
        print("Document does not exist")
    }
}

Solution 4

In Swift 3

    let ref = Database.database().reference()
    let uid = Auth.auth().currentUser?.uid
    let usersRef = ref.child("users").child(uid!)

    // only need to fetch once so use single event
    usersRef.observeSingleEvent(of: .value, with: { snapshot in

        if !snapshot.exists() { return }

        //print(snapshot)

        let userInfo = snapshot.value as! NSDictionary
        print(userInfo)
        print(userInfo["name"]!)
        let profileUrl = userInfo["profilePicUrl"] as! String

        print(profileUrl)
        let storageRef = Storage.storage().reference(forURL: profileUrl)
        storageRef.downloadURL(completion: { (url, error) in
            let data = Data(contentsOf: url!)
            let image = UIImage(data: data! as Data)
            self.profilePic.image = image
        })

This downloads the image from storage.

Share:
29,538
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I am looking for a beginning to end code example of retrieving an image from Firebase Storage, just to show an image. Either as an image view or for a table. I have looked at posts on here and various tutorials. It always feels like something is left out. If I could see the whole picture, I will be able to grasp this better.

    The attached code is my current attempt to change photo1 from local to pull from Firebase Storage.

    import UIKit
    import Firebase
    import FirebaseAuth
    import FirebaseStorage
    import FirebaseDatabase
    
    class MainMenuTableViewController: UITableViewController {
    
    
    
    var mainMenu = [Menu]()
    var photo1 = UIImage()
    override func viewDidLoad() {
        super.viewDidLoad()
        loadMenu()
    }
    
    func loadMenu() {
    
        let storage = FIRStorage.storage()
        // Create a storage reference from the URL
        let storageRef = storage.referenceForURL("https://firebasestorage.googleapis.com/v0/b/medicalpatientapp-7fd45.appspot.com/o/iconimages%2Ffile-medical-icons.png?alt=media&token=c95b9c51-67ae-4e93-b63c-62091015a9ff")
        // Download the data, assuming a max size of 1MB (you can change this as necessary)
        storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
            // Create a UIImage, add it to the array
            let pic = UIImage(data: data!)
            self.photo1 = pic!
    
        }
    
    
       //let photo1 = UIImage(named: "iconimages-file-medical-icons")!
        let menu1 = Menu(name: "My Notes", photo: photo1)!
    
        let photo2 = UIImage(named: "iconimages-file-medical-icons")!
        let menu2 = Menu(name: "View Patients", photo: photo2)!
    
        let photo3 = UIImage(named: "iconimages-add-medical-icons")!
        let menu3 = Menu(name: "Add Persons", photo: photo3)!
    
        mainMenu += [menu1, menu2, menu3]
    
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // MARK: - Table view data source
    
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return mainMenu.count
    }
    
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
    
        // Configure the cell...
        let cellIdentifier = "MenuTableViewCell"
        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! MainMenuTableViewCell
    
        // Fetches the appropriate meal for the data source layout.
        let menu = mainMenu[indexPath.row]
    
        cell.menuLabel.text = menu.name
        cell.menuImage.image = menu.photo
    
        return cell
    }
    

    }

  • Admin
    Admin almost 8 years
    Thank you. For the download, is that pulling everything from "myfiles" or do you have to do this for each? Can Firebase storage be used on its own without the database? I have seen the "Zero To App" in a previous post, I am not using this to attach to a user profile at this time, and it was not as straight forward as your example.
  • Mike McDonald
    Mike McDonald almost 8 years
    Firebase Storage is designed to be used independently. That said, it's much easier to list and retrieve files by using it in conjunction with the Realtime Database. This example will retrieve all of the files stored at the database location "myFiles", which has been populated by the uploads to "myFiles/{fileName}".