t2k
t2k

Reputation: 41

Firebase image is empty after switching views in SwiftUI

I'm trying to display images from a list of objects stored in Firebase. Initially the image loads fine, but if I switch to a different view and return to the list view the image never loads again.

Gif of the described bug

The image data seems to be saved as expected on both load attempts: here

Below is my code for the image loader, which uses a url to fetch the images from Firebase Storage, and the list row that contains the image.

ImageLoader.swift

import Foundation
import SwiftUI
import Firebase
import FirebaseFirestore

class ImageLoader: ObservableObject {
    @Published var dataIsValid = false
    var data:Data?

    func loadImage(url: String) {
        let imageRef = Storage.storage().reference(forURL: url)
        imageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
            if let error = error {
                print("\(error)")
            }
            guard let data = data else { return }
            DispatchQueue.main.async {
                print(self.dataIsValid)
                self.dataIsValid = true
                self.data = data
            }
        } 
    }

    func imageFromData() -> UIImage {
        UIImage(data: self.data!)!
    }
}

ListRow.swift

import SwiftUI
import Combine

struct EventRow: View {
    @ObservedObject var imageLoader = ImageLoader()
    var imageUrl: String

    var body: some View {
        HStack {
            Image(uiImage: self.imageLoader.dataIsValid ? self.imageLoader.imageFromData() : UIImage())
            .resizable()
            .frame(width: 100.0, height: 140.0)
            .background(Color.gray)
            .clipShape(RoundedRectangle(cornerRadius: 5.0))

        }
        .onAppear {
            self.imageLoader.loadImage(url: self.imageUrl)
        }
    }
}

Upvotes: 1

Views: 1006

Answers (1)

t2k
t2k

Reputation: 41

The way I fixed this was by creating a custom ImageView and handling the image loading within this view. I figured this out by following this tutorial and realized that was the step I was missed. If anyone can explain why using the built-in SwiftUI Image() causes this issue I would really appreciate it.

ListRow.swift

import SwiftUI

struct ListRow: View {
    var imageUrl: String

    var body: some View {
        HStack {
            FBURLImage(url: imageUrl)
        }
    }
}

FBURLImage.swift

import SwiftUI

struct FBURLImage: View {
    @ObservedObject var imageLoader: ImageLoader

    init(url: String) {
        imageLoader = ImageLoader()
        imageLoader.loadImage(url: url)
    }

    var body: some View {
        Image(uiImage:
            imageLoader.data != nil ? UIImage(data: imageLoader.data!)! : UIImage())
            .resizable()
            .frame(width: 100.0, height: 140.0)
            .background(Color.gray)
            .clipShape(RoundedRectangle(cornerRadius: 5.0))
    }
}

ImageLoader.swift

import Foundation
import SwiftUI
import Firebase
import FirebaseFirestore

class ImageLoader: ObservableObject {
    @Published var data: Data?

    func loadImage(url: String) {
        let imageRef = Storage.storage().reference(forURL: url)
        imageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
            if let error = error {
                print("\(error)")
            }
            guard let data = data else { return }
            DispatchQueue.main.async {
                self.data = data
            }
        }
    }
}

Upvotes: 3

Related Questions