genericsswiftuitype-erasuresubscript

Cannot access generic subscript


I have this code in library so I cannot modify it.

public enum StepperIndicationType<Content:View> {
    public typealias Width = CGFloat

    case circle(Color, Width)
    case image(Image, Width)
    case animation(NumberedCircleView)
    case custom(Content)
}

I did created entity of type StepperIndicationType with case custom and passed view with property name

struct MyView: View {
    var name: String
    var body: some View {
       Image(name)
    }

I did created array of views of that type in my HostController

@State var indicators = [
StepperIndicationType.custom(MyView(name: "pending")),
                         .custom(MyView(name: "pending")),
                         .custom(MyView(name: "pending")),
                         .custom(MyView(name: "pending"))]

Then I am trying get access to value at index to change property name to different image but I am getting a message Value of type StepperIndicationType<MyView> has no member name

indicators[3].name = "completed"

Xcode shows me what I have type like this:

let obj = indicators[3]

[option click on obj shows me this type] :

StepperIndicationType<MyView>

I am struggling to figure out what I did wrong and why I can't get access to property of object at index in array


Solution

  • Just use a [String]:

    @State var indicators = ["pending", "pending", "pending", "pending"]
    

    This makes it easy to update the array:

    indicators[3] = "completed"
    

    Only convert the array into [StepperIndicationType<MyView>] at the last minute.

    StepperView()
        // ...
        .indicators(indicators.map { .custom(MyView(name: $0)) })
        // ...
    

    Alternatively, you can add a name property to StepperIndicationType in an extension, though I find this quite ugly.

    extension StepperIndicationType<MyView> {
        var name: String? {
            get {
                if case let .custom(content) = self {
                    content.name
                } else {
                    nil
                }
            }
            set {
                if case var .custom(content) = self, let newValue {
                    content.name = newValue
                    self = .custom(content)
                }
            }
        }
    }
    

    Then indicators[3].name = "completed" would compile.