0

I want to display an image (type UIImage) which is stored in an EnvironmentObject. This EnvironmentObject consists of an array of a structure which holds an UIImage element. In a view, I want to display an image of this array but this doesn't work somehow.

Here's the struct:

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

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

Here the ModelData class:

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

And this is the instantiation of modelData in the main app code:

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

The content of the modelData is loaded from a Firebase database and Firebase storage. This actually works, I can see the downloaded images in the modelData.testStruct[...].image in the debug preview.

From a view, I want to reference the image from the 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)           
        }
    }
}

Can someone help me? I'm generally confused with ObservableObject/EnvironmentObject and that stuff but I was able to display e.g. the field "name" of modelData.testStruct[0] in a TextView. Is the passing of the UIImage to the Image view wrong, maybe? Or something else needed there?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • Welcome to Stack Overflow! Please take the [tour](https://stackoverflow.com/tour) and see: [How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) and [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). No where in your shown code did you assign anything to your `TestStruct.image` other than a blank image. That, obviously, will show nothing. Also, you really shouldn't be putting an image in there, rather it should be the reference of where to find it. Images get pretty big, and you are making an array of the things... – Yrb Dec 23 '21 at 15:38
  • Thanks for the reply. The structure array is filled by other functions (downloads from FirebaseStorage). The pictures are actually quite small (about 10-100kB) but you're right. The proposal would be to save the downloaded pictures in the global memory / as assets? How can I add pictures as assets during runtime? – swiftdevappbk Dec 23 '21 at 15:47
  • Google is your friend here. There is no reason to reinvent the wheel, and there are numerous examples and tutorials on how to build this particular wheel. But, why would you need to download them ahead of time? If you are using an online database, download them when you need them. – Yrb Dec 23 '21 at 15:51
  • Sure, I will google how to store downloaded pictures on the device (btw the Firestone libs bring already caching). But I still don't understand why my current code doesn't show the picture that is stored in modelData.testStruct[0].image – swiftdevappbk Dec 23 '21 at 17:28
  • As I said in my first comment, no where in the code you posted do you set `TestStruct.image` to anything but a blank image. When you initialize it with `UIImage.init()` you are telling your app to store a blank image there. Where do you change this? – Yrb Dec 23 '21 at 17:38

1 Answers1

0

In the getData completion callback of Firestone, it's set:

let reference = Storage.storage().reference(forURL: tempStruct.imageUrl)
                                reference.getData(maxSize: (1 * 1024 * 1024)) { (data, error) in
    if let _error = error{
      print(_error)
    } else {
      if let _data  = data {
        tempStruct.image = UIImage(data: _data)!
      }
    }
}

...

modelData.testStruct.append(tempStruct)

This is done when the App is started. The image will/shall then be later shown when the user goes to another menu item.

Solution:

The image of the testStruct type had to be changed to @Published, therefore it was also needed to change testStruct to a class:

class TestStruct: ObservableObject {
    var id: String
    var name: String
    @Published var image: UIImage

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