0

My data model:

class MyData: ObservableObject {
    @Published var aabbData = [AabbData]()
}

struct AbData: AabbData{
    var x = 0
}

protocol AabbData{

}

In my view code, i want to downcast aabbData's element to AbData type, and bind its x property to a control's value. So i try to code this:

@EnvironmentObject var data: MyData
let index = 0

//some other code

//method 1
Slider(value: ($data.aabbData[index] as! Binding<AbData>).x, in: -100...100, step: 1)
//error: Cast from 'Binding<AabbData>' to unrelated type 'Binding<AbData>' always fails

//method 2
Slider(value: Binding<Int>(
    get:{
        (data.aabbData[index] as! AbData).x
    },
    set:{
        (data.aabbData[index] as! AbData).x = $0
        //error: Cannot assign to immutable expression of type 'Int'
    }
), in: -100...100, step: 1)

The code is not working. How can i bind the downcast value's property to control's value?

3
  • Generic types of related types aren't themselves related in Swift. In other words, Foo<A> is as different from Foo<B> as any other type, even if A: B Commented Aug 14, 2020 at 15:11
  • 2
    If you're going force-cast then aabbData is always [AbData] then there is no sense in this artificial making it [AabbData] at all. And by the way in majority of cases forget about casting in SwiftUI, for easiness and safeness of project code. Commented Aug 14, 2020 at 15:11
  • It's simplified code, aabbData is a array contains multiple different struct type. Commented Aug 14, 2020 at 15:22

1 Answer 1

3

The Binding type allow for both reading and writing. Since you can't safely read the value of an AabbData and assume it's an AbData this cannot work.

If you want to try anyway, then you'll have to create a new Binding (possibly with the Binding(get:set:) constructor) that does the casting there.

For example, noting that this forced cast is probably not advisable for all the usual reasons:

let binding = Binding<AbData>(get: {
    data.aabbData[index] as! AbData
}, set: {
    data.aabbData[index] = $0
})
Sign up to request clarification or add additional context in comments.

5 Comments

thanks. I try to create a new binding, but fail to create a correct setter to make data binding working. Could you show some code?
@swiftrustar sure
It's strange that there is no generic way of doing this. Rebinding works though. As shown in this example. Thanks!
@Sentry.co It's not so strange really, as this is essentially bypassing the type system. The type system makes this difficult to do because it's usually a bad idea, but forced downcasts allow the developer to assert that they know what they're doing, and to crash if they get it wrong.
I've found that this method causes my views to constantly redraw themselves.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.