I'm trying to create a custom Stack type for my application, exploiting the fact that its children conform to a custom protocol. Desired end-goal is
where MyView, MyView 2, etc. conform to some protocol, and in the implementation of DStack we use the protocol in some way on the child elements. For example, we apply a similar configuration to the elements, or interrogate the elements to configure the stack itself.
For my first attempt:
This produces
However, since in Swift tuples are non-nominal we can't do this.
Maybe the problem here is TupleView, and I need to traffic in my own view-group type, perhaps that models its storage as an array or something. This would require my own functionbuilder. Here's a sketch of that...
The return value... cannot be erased, because eventually we need to create a SwiftUI ZStack, and it wants to know how many arguments there are and so on.
I'm stumped. What's the right way to do this?
Code Block swift DStack { MyView() MyView2() //etc. }
where MyView, MyView 2, etc. conform to some protocol, and in the implementation of DStack we use the protocol in some way on the child elements. For example, we apply a similar configuration to the elements, or interrogate the elements to configure the stack itself.
For my first attempt:
Code Block swift import SwiftUI import PlaygroundSupport protocol Foo: View { func foo() } struct MyView1: Foo { var body: some View { Text("Hello world") } func foo() { preconditionFailure("implement this") } } struct DStack<Content>: View where Content: Foo { let builder: () -> Content init(@ViewBuilder content: @escaping () -> Content) { builder = content } var body: some View { ZStack(content: builder) //additional customization here exploiting conformance to Foo } } struct Demo: View { var body: some View { DStack { MyView1() MyView1() } } } PlaygroundPage.current.setLiveView(Demo())
This produces
Ok, fair enough. The obvious solution here is to apply a conditional conformance TupleView: Foo, which very roughly would beGeneric struct 'DStack' requires that 'TupleView<(MyView1, MyView1)>' conform to 'Foo'
Code Block swift //conform TupleView.T extension (T,V): Foo where T: Foo, V: Foo { ...} //conditionally conform TupleView extension TupleView: Foo where T: Foo { ... }
However, since in Swift tuples are non-nominal we can't do this.
Maybe the problem here is TupleView, and I need to traffic in my own view-group type, perhaps that models its storage as an array or something. This would require my own functionbuilder. Here's a sketch of that...
Code Block swift @_functionBuilder struct FooBuilder { static func buildBlock(_ children: Foo...) -> Foo { //... } }
So we need existentials for both the arguments and return type. The arguments are "straightforward", just create a type-erased wrapper.Protocol 'Foo' can only be used as a generic constraint because it has Self or associated type requirements
The return value... cannot be erased, because eventually we need to create a SwiftUI ZStack, and it wants to know how many arguments there are and so on.
I'm stumped. What's the right way to do this?