Skip to content

StorageUI with SwiftUI  #1109

Closed
Closed

Description

@micheau-bastien

StorageUI with SwiftUI

Description

I have been browsing to find SwiftUI Image Compatibility with FirebaseUI Storage and did not find anything that suited my need so I built a little helper class. This class syncs it's cache with UIKit existing StorageUI cache in order to avoid doubling the data consumption and cache size.

This work is heavily inspired from Ben McMahen's great article : https://benmcmahen.com/firebase-image-in-swiftui/

Feel free to reuse this !

Code

import Foundation
import SwiftUI
import FirebaseStorage
import SDWebImage
import FirebaseStorageUI

// TODO - Replace placeholder string to asset from your project
let placeholder = UIImage(named: "placeholder")!

/// SwiftUI View that will display placeholder, then Firebase Storage Image
struct StorageUIImage : View {
  
  /// Init
  /// - Parameter path: firebase path of the image (ex.: "storageFolder/subfolder/filename.jpg")
  init(path: String) {
      self.imageLoader = LiveLoader(path)
  }
  
  /// Image Loader observed object that will trigger image changes.
  @ObservedObject private var imageLoader: LiveLoader
  
  var body: some View {
      Image(uiImage: imageLoader.image ?? placeholder)
  }
}

/// LiveLoader class that will try to return image from memory cache, then disk cache, then network.
final class LiveLoader : ObservableObject {
  /// Published image object to be observed
  @Published var image: UIImage? = nil
  
  init(_ path: String){
      let storage = Storage.storage()
      let ref = storage.reference().child(path)
      let url = NSURL.sd_URL(with: ref) as? URL
      if let image = SDImageCache.shared.imageFromCache(forKey: SDWebImageManager.shared.cacheKey(for: url)) {
          // If image was present form memory cache, we display it
          print("Image loaded from memory cache")
          self.image = image
      } else if let image = SDImageCache.shared.imageFromDiskCache(forKey: SDWebImageManager.shared.cacheKey(for: url)) {
          // Else if image was present form disk cache, we cache it in memory again and display it
          print("Image loaded from disk cache")
          SDImageCache.shared.store(self.image, forKey: SDWebImageManager.shared.cacheKey(for: url), toDisk: false) {
              self.image = image
          }
      } else {
          // Else we fetch it from network, cache it in memory and disk, then display it
          print("Image downloaded")
          // maxSize can be set as parameter if needed
          ref.getData(maxSize: 1 * 1024 * 1024) { data, error in
              if let error = error {
                  print("\(error)")
              }
              guard let data = data else { return }
              SDImageCache.shared.store(self.image, forKey: SDWebImageManager.shared.cacheKey(for: url)) {
                  DispatchQueue.main.async {
                      self.image = UIImage.init(data: data)
                  }
              }
          }
      }
  }
}

Open points

  • Usage of @StateObject instead of @observableobject
  • Real testing of the load from disk without cache present was not done
  • Operators like .resizable()don't work on StorageUIImage view

Activity

  1. micheau-bastien commented on Oct 15, 2022

    @micheau-bastien
    Author

    Linked to #811 that covers other FirebaseUI's parts in SwiftUI

  2. morganchen12 commented on Oct 19, 2022

    @morganchen12
    Contributor

    Thanks @micheau-bastien! Would you like to contribute this as a PR?

  3. reopened this on Jun 9, 2026
  4. github-actions commented on Jul 8, 2026

    @github-actions

    Hello, to help manage issues we automatically close stale issues.

    This issue has been automatically marked as stale because it has not had activity for quite some time. If it is still relevant, leave a comment to keep it open.

    This issue will be closed in 15 days if no further activity occurs.

    Thank you for your contributions.

  5. russellwheatley commented on Aug 3, 2026

    @russellwheatley
    Member

    Closing out, user is still welcome to open a PR with this update and I'm happy to review it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions