Home > database >  How can I change return view type from <TupleView<(View, View)>> to <_> for initia
How can I change return view type from <TupleView<(View, View)>> to <_> for initia

Time:03-18

I have a view that return a view in form of <TupleView<(View, View)>>, like this: enter image description here

Also I have a view that return a view in form of <_>, like this: enter image description here

With knowing that both way works and my wished way is using TupleView under cover but having the look of <_>, I tried to work on MyView3, as you can see in my tried codes I want this look of (content: () -> _) -> MyView3<_> for being more simple and understandable, but i need TupleView way initialization undercover. I got 3 error's for MyView3 to make it work. Do you think is there a way for my goal?

For more information see this codes:

struct ContentView: View {
    var body: some View {
        
        MyView1(content: {
            Text("Text 1").fixedSize()
            Text("Text 2").fixedSize()
        })
            .padding()

        MyView2(tupleViewContent: {
            Text("Text 3").fixedSize()
            Text("Text 4").fixedSize()
        })
            .padding()

        // This part has issue!
        MyView3(content: {
            Text("Text 5").fixedSize()
            Text("Text 6").fixedSize()
        })
            .padding()

    }
}

struct MyView1<Content: View>: View {
    
    let content: () -> Content
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }
    
    var body: some View {
        content()
    }
}

struct MyView2<Content: View>: View {
    
    let content: () -> Content
    
    init<Content1: View, Content2: View>(@ViewBuilder tupleViewContent: @escaping () -> Content) where Content == TupleView<(Content1, Content2)> {
        self.content = tupleViewContent
    }
    
    var body: some View {
        content()
    }
}

struct MyView3<Content: View>: View {

    let content: () -> Content

    private init<Content1: View, Content2: View>(@ViewBuilder tupleViewContent: @escaping () -> Content) where Content == TupleView<(Content1, Content2)> {
         self.content = tupleViewContent
    }
    
    init(@ViewBuilder content: @escaping () -> Content) {
        
        //Error:
        // Generic parameter 'Content1' could not be inferred
        // Generic parameter 'Content2' could not be inferred
        // Initializer 'init(tupleViewContent:)' requires the types 'Content' and 'TupleView<(Content1, Content2)>' be equivalent
        self.init(tupleViewContent: content)
        
    }
    
    var body: some View {
        content()
    }
}

CodePudding user response:

The generics is resolved at compilation time, so init/s should go from more specific to more common (finally to the designated one).

In your case it should be like (tested with Xcode 13.2)

struct MyView3<Content: View>: View {

    let content: () -> Content

    init<Content1: View, Content2: View>(@ViewBuilder tupleViewContent: @escaping () -> Content) where Content == TupleView<(Content1, Content2)> {
         self.init(content: tupleViewContent)
    }

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        content()
    }
}
  • Related