Reputation: 10877
I'm using a protocol to define an override to the default View
protocol to create some templated views in my app. They will all share the same CalculationComponent
view for the bulk of the layout but then will implement different buttons / controls that are passed through with a @ViewBuilder
which uses generics.
The issue I'm having is that when defining my protocol body, the generic type is throwing an error where Type 'any View' cannot conform to 'View'
. I think this has directly to do with the <Content: View>
part on CalculationComponent
CalculationComponent.swift
struct CalculationComponent<Content: View>: View {
@Binding var mainCalculation: String
@Binding var secondaryCalculation: String
@ViewBuilder var content: () -> Content
var body: some View {
// Template UI here
content()
}
}
CalculationView.swift
protocol CalculationView: View {
var mainCalculation: String { get set }
var secondaryCalculation: String { get set}
var body: CalculationComponent<View> { get } // Type 'any View' cannot conform to 'View'
}
CalculatorView.swift
struct CalculatorView: CalculationView {
@State internal var mainCalculation: String = ""
@State internal var secondaryCalculation: String = ""
var body: CalculationComponent {
CalculationComponent(
mainCalculation: $mainCalculation,
secondaryCalculation: $secondaryCalculation
) {
Text("Buttons and view content here")
}
}
}
Upvotes: 20
Views: 43674
Reputation: 271420
If I understand correctly, you want a specialised version of the View
protocol, where Body
is CalculationComponent<some View>
, and you don't want to write explicitly what "some View
" is when conforming to the protocol, plus some other requirements.
You can add an associated type to CalculationView
,
protocol CalculationView: View {
associatedtype Content: View
var mainCalculation: String { get set }
var secondaryCalculation: String { get set}
var body: CalculationComponent<Content> { get }
}
and then say CalculationComponent<some View>
when conforming to the protocol:
struct CropFactorCalculatorView: CalculationView {
@State internal var mainCalculation: String = ""
@State internal var secondaryCalculation: String = ""
var body: CalculationComponent<some View> {
CalculationComponent(
mainCalculation: $mainCalculation,
secondaryCalculation: $secondaryCalculation
) {
VStack {
Text("Some Text")
Text("Some Other Text")
}
}
}
}
Upvotes: 14