1

I am trying to accomplish something that looks pretty simple: I have a custom Image subclass in SwiftUI which I’m using for convenience, and I would like to use it in my app. My end goal is to use the OnboardingThumbnailImage in other views and simply pass an image name to the constructor.

import SwiftUI

struct OnboardingThumbnailImage: View {
    var imageName: String

    var body: some View {
        Image(imageName)
            .resizable()
            .scaledToFit()
            .frame(width: 50, height: 50)
            .foregroundColor(Colors.tintColor)
    }
}

struct OnboardingThumbnailImage_Previews: PreviewProvider {
    static var previews: some View {
        OnboardingThumbnailImage(imageName: "?????")
    }
}

How can I accomplish this? The compiler requires me to specify a value inside OnboardingThumbnailImage_Previews so I have no clue. I have looked into Bindings but I don't need a 'two-way street' between the views, so I'm not sure.

Can I instead just perhaps leave Image() with no arguments inside, in order to inherit the default Image constructor? If I leave Image() I get an error: Cannot invoke initializer for type 'Image' with no arguments.

Cesare
  • 9,139
  • 16
  • 78
  • 130
  • you can define your imageName as empty string. `var imageName: String = ""` and priview ignore it – Mac3n Feb 21 '20 at 19:06

2 Answers2

2

This is SwiftUI's way of asking you

What image do you want to show when this View is previewed?

You can only preview SwiftUI views on macOS Catalina, so if you are not using Catalina (like me), then this feature is not very relevant to you.

You are supposed to put the image that you want to see in the previews in the ???? bit. If you are not using Catalina, or you just don't want to preview it, you can just delete the whole OnboardingThumbnailImage_Previews struct.

Also note that you can't "subclass" another view in SwiftUI. All you can do is composition, which is what you have done here. SwiftUI's design favours composition over inheritance. You can find explanations of this concept in these pages: 1, 2.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thank you! What if I want to preview _the image_ I specify in the parent view? I don't understand how I can "pass it" to that file it that makes sense. – Cesare Feb 22 '20 at 12:46
  • Does the fact that SwiftUI's design favors composition over inheritance mean I should rather not create a new file for the custom image? – Cesare Feb 22 '20 at 12:47
  • Again, you can delete the `OnboardingThumbnailImage_Previews` struct (since you don't need to preview `OnboardingThumbnailImage` itself), and pass in image name in the preview struct of your parent view. @Cesare – Sweeper Feb 22 '20 at 12:48
  • @Cesare What gives you that impression? Files are rather irrelevant here. They are just a way to organise your code. How you organise your code is up to you. – Sweeper Feb 22 '20 at 12:49
  • I do have Catalina though. Give me a sec while I go through everything you wrote. Thanks so much for your help in the meantime. Yeah for files I meant creating a new class sorry – Cesare Feb 22 '20 at 12:54
  • Are you able to see the preview of the parent view of `OnboardingThumbnailImage` then? @Cesare Composition doesn't mean that you shouldn't create your own types. It means your own types should "contain" other types, instead of inheriting from other types. The two links I provided explains this quite well. – Sweeper Feb 22 '20 at 12:55
  • Yes, I'm able to see the preview of the parent view of `OnboardingThumbnailImage `. Deleting `OnboardingThumbnailImage_Previews` deletes the preview as you suggested. So from my understanding `OnboardingThumbnailImage_Previews` is for when we want to preview `OnboardingThumbnailImage` _only_, correct? Therefore I need to assign `imageName` a _default_ value if I want to preview something? – Cesare Feb 22 '20 at 13:03
0

In your struct view, the variable imageName needs value for initialization. as it should be string, because you define a string variable and use it in your Image. To ignore the error you can set an empty value to your variable to ignore the requirement to init in view construction

var imageName: String = ""
Mac3n
  • 4,189
  • 3
  • 16
  • 29
  • Thanks, then what steps do I need to take to make it an `Image` subclass? Renaming `[...] : View` into `[...] : Image` doesn't work. – Cesare Feb 21 '20 at 19:22
  • There is no subclassing in SwiftUI Views because they are all structs that conforms to View protocol and not a class type. you can't subclass to Image because Image is a view itself – Mac3n Feb 21 '20 at 19:26