swiftswiftuiviewbuilder

Cannot convert value of type 'TupleView<(Text, Text)>' to closure result type 'Text'


I am trying to understand why I keep getting an error when I try to use this custom layout view I've created.

Here is the error (also commented in the code below):

Cannot convert value of type 'TupleView<(Text, Text)>' to closure result type 'Text'

And here is the code that generates the problem.

struct BaseRecordView_Previews: PreviewProvider {
    static var previews: some View {

        // Error: Cannot convert value of type 'TupleView<(Text, Text)>' 
        // to closure result type 'Text'
        BaseRecordView() { 
            Text("125.6")
            Text("kg")
        } subHeading: {
            Text("44.1 BMI")
        } content: {
            Text("Something here")
        }

    }
}

and this is how I have defined BaseRecordView:

struct BaseRecordView<Content: View>: View {
    @ViewBuilder var heading: Content
    @ViewBuilder var subHeading: Content
    @ViewBuilder var content: Content
    
    init(
         @ViewBuilder heading: @escaping () -> Content,
         @ViewBuilder subHeading: @escaping () -> Content,
         @ViewBuilder content: @escaping () -> Content)
    {
        self.heading = heading()
        self.subHeading = subHeading()
        self.content = content()
    }
    
    var body: some View {
        // layout content here
        heading
        subHeading
        content
    }
}

What am I missing here? What is the meaning of TupleView<(Text, Text)> in this context?


Solution

  • The problem is that you declared your BaseRecordView with all 3 of its generic View properties having the same Content type, but you are passing a different type of view to heading that to subHeading and content.

    If you want to be able to pass 3 different types of Views, you need 3 different generic type parameters.

    struct BaseRecordView<Heading: View, Subheading: View, Content: View>: View {
        @ViewBuilder private let heading: Heading
        @ViewBuilder private let subHeading: Subheading
        @ViewBuilder private let content: Content
    
        init(
             @ViewBuilder heading: @escaping () -> Heading,
             @ViewBuilder subHeading: @escaping () -> Subheading,
             @ViewBuilder content: @escaping () -> Content)
        {
            self.heading = heading()
            self.subHeading = subHeading()
            self.content = content()
        }
    
        var body: some View {
            // layout content here
            heading
            subHeading
            content
        }
    }
    
    struct BaseRecordView_Previews: PreviewProvider {
        static var previews: some View {
    
            // Error: Cannot convert value of type 'TupleView<(Text, Text)>'
            // to closure result type 'Text'
            BaseRecordView() {
                Text("125.6")
                Text("kg")
            } subHeading: {
                Text("44.1 BMI")
            } content: {
                Text("Something here")
            }
    
        }
    }