swiftui - Cannot access generic subscript - Stack Overflow

时间: 2025-01-06 admin 业界

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

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

Share Improve this question asked yesterday DanilDanil 6310 bronze badges 3
  • Do I need to downcast it somehow to concrete type and how I can do it to get access to "name" property ? – Danil Commented yesterday
  • 1 Are indicators guaranteed to contain only custom indicators? If so, why not just change it to a [String] storing all the names instead? – Sweeper Commented yesterday
  • yes, indicators array have only custom all the time. I pass that array and "inject" it as .indicators view modifier to a different View to construct it. That behaviour is required by lib. StepperView() .addSteps(steps) .stepLifeCycles(lifeCycles) .indicators(indicators) .lineOptions(StepperLineOptions.rounded(4, 8, .blue)) .stepIndicatorMode(StepperMode.vertical) .spacing(30) – Danil Commented 23 hours ago
Add a comment  | 

1 Answer 1

Reset to default 1

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.