es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La imagen de SwiftUI no muestra una UIImage desde una variable.

Quiero mostrar una imagen (tipo UIImage) que se encuentra almacenada en un EnvironmentObject. Este EnvironmentObject consiste en un array de una estructura que contiene un elemento UIImage.
En una vista, quiero mostrar una imagen de este array pero de alguna manera esto no funciona.

Aquí está la estructura:

struct TestStruct: Identifiable {
    var id: String
    var name: String
    var image: UIImage

    init() {
        id = ""
        name = ""
        image = UIImage.init()
    }
}

Aquí está la clase ModelData:

final class ModelData: ObservableObject {
    @Published var testStruct: [TestStruct] = []
}

Y esta es la instanciación de modelData en el código principal de la aplicación:

struct TestApp: App {
    @ObservedObject private var modelData = ModelData()
    init() {...

El contenido de modelData se carga desde una base de datos de Firebase y el almacenamiento de Firebase. Esto funciona correctamente, puedo ver las imágenes descargadas en modelData.testStruct[…].image en la vista de depuración.

Desde una vista, quiero hacer referencia a la imagen desde modelData:

struct StructContentView: View {
    @EnvironmentObject var modelData: ModelData

    var body: some View {
        ScrollView {
            Image(uiImage: modelData.testStruct[0].image)
                .frame(width: 64.0, height: 64.0)
                .foregroundColor(.red)           
        }
    }
}

¿Alguien puede ayudarme? Estoy confundido en general con ObservableObject/EnvironmentObject y esas cosas, pero pude mostrar, por ejemplo, el campo “nombre” de modelData.testStruct[0] en un TextView. ¿Está mal pasar UIImage a la vista de Image, tal vez? ¿O se necesita algo más allí?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Parece que el problema podría estar relacionado con el momento en que la imagen se carga en modelData en comparación con cuando se accede en la vista. Dado que cargar la imagen desde Firebase storage puede llevar tiempo, es posible que la vista intente acceder a la imagen antes de que se haya descargado y almacenado en modelData.

    Una solución podría ser utilizar un modelo de vista separado que solo cargue la imagen una vez que esté disponible, y luego actualice la vista con la imagen. Esto aseguraría que la vista solo intente acceder a la imagen una vez que esté realmente disponible.

    Otro enfoque podría ser utilizar una declaración condicional en la vista para solo mostrar la imagen una vez que se haya cargado. Por ejemplo:

    struct StructContentView: View {
        @EnvironmentObject var modelData: ModelData
        @State private var isImageLoaded = false
    
        var body: some View {
            ScrollView {
                if isImageLoaded {
                    Image(uiImage: modelData.testStruct[0].image)
                        .frame(width: 64.0, height: 64.0)
                        .foregroundColor(.red)
                } else {
                    Text("Cargando imagen...")
                }
            }
            .onAppear {
                // Cargar la imagen de forma asíncrona
                loadImageAsync()
            }
        }
    
        private func loadImageAsync() {
            guard modelData.testStruct.count > 0 else {
                return
            }
            let url = URL(string: "ruta/a/la/imagen/en/firebase-storage.jpg")! // Reemplazar con la ruta de la imagen real
            URLSession.shared.dataTask(with: url) { data, response, error in
                if let data = data, let image = UIImage(data: data) {
                    DispatchQueue.main.async {
                        modelData.testStruct[0].image = image
                        isImageLoaded = true
                    }
                }
            }.resume()
        }
    }
    

    Este código utiliza una bandera booleana (isImageLoaded) para verificar si la imagen se ha cargado o no. En la representación inicial de la vista, la bandera es false y la vista muestra un texto para indicar que la imagen se está cargando. Mientras tanto, se llama a la función loadImageAsync, que carga la imagen de forma asíncrona utilizando URLSession.shared.dataTask. Una vez que se ha cargado la imagen, se almacena en modelData y la bandera se establece en true, lo que provoca que la vista se actualice y muestre la imagen.

Comments are closed.