Download Image for Firebase Storage inside a SwiftUI Listview (contact app)

Viewed 666

I'm new in Swift and I'm trying to display inside a SwiftUI ListView :

  • some datas
  • an image (linked to datas)

It's kind of a contact app.

All these datas are stored in firestore. I created a function which gives the image URL on firestore :

func getURL(path: String, completion: @escaping (((URL?) -> Void))) {
    let storage = Storage.storage()
    storage.reference().child(path).downloadURL(completion: { url, error in
        guard let url = url, error == nil else {
            return
        }
        let urlPath = url.absoluteURL
        completion(urlPath)
    })
}

But when i call this function in the SwiftUI View, the following error appears :

"Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols"

There is the calling code of the function :

getURL(path: bike.access1, completion: { path in AnimatedImage(url: path)})

I'm aware that i can't call function inside a view, but i don't see how to manage to display an image from Firestore inside a SwiftUI List View. If anyone know a strategy, I'm really interested. Thanks in advance Jean

1 Answers

The completion handler is (in general) a great way of dealing with asynchronous code. But, it a View in SwiftUI, it's a little more common to use a @State or @Published value and then render the view conditionally based on its state.

I like using an ObservableObject view model for this sort of thing:

class ViewModel : ObservableObject {
    @Published var imageURL : URL?
    
    func getURL(path: String) {
        let storage = Storage.storage()
        storage.reference().child(path).downloadURL(completion: { url, error in
            guard let url = url, error == nil else {
                return
            }
            self.imageURL = url
        })
    }
}

struct ContentView : View {
    @StateObject private var viewModel = ViewModel()
    
    var body: some View {
        VStack {
            if let url = viewModel.imageURL {
                AnimatedImage(url: url)
            }
        }.onAppear {
            viewModel.getURL(path: "URL_STRING_GOES_HERE")
        }
    }
}

Note that my types

Related