simibac
simibac

Reputation: 8610

Passing functions with State variable to Child View

I am trying to pass different functions to child view. For that I use typalias and different initialisers.

I get an Error when I try to pass a @State-variable. How do I need to set the Binding-variable in the child view?

Error is as follows:

Cannot assign value of type 'Bool' to type 'Binding'

Here is my code:

typealias OnTabHandler = (String) -> Void

struct ContentView: View {
    @State var showSheet = false

    var onTabHandler:OnTabHandler = { text in
        print(text)
    }

    var body: some View{
        VStack{
            // print to console
            ChildView(text: "Hello", onTabHandler: onTabHandler)

            // show sheet
            ChildView()
                .sheet(isPresented:$showSheet){ Text("sheet view")}
        }
    }
}

struct ChildView:View{
    var text:String
    var onTabHandler:OnTabHandler
    var showSheet:Binding<Bool>

    // print to console
    init(text:String, onTabHandler:@escaping OnTabHandler){
        self.text = text
        self.onTabHandler = onTabHandler
        self.showSheet = Binding.constant(false)
    }

    // show sheet
    init(showSheet:Binding<Bool>){
        self.showSheet = showSheet
        self.onTabHandler = {_ in

            // Error here
            self.showSheet = true
        }
        self.text = ""
    }

    var body: some View{
        Button("Tab Me"){
            self.onTabHandler(self.text)
        }
    }
}

Upvotes: 4

Views: 1763

Answers (2)

lorem ipsum
lorem ipsum

Reputation: 29614

See below for the two constructors.

Tip: Using .constant is only considered acceptable during prototyping. I will look for the apple reference but it is mentioned here under "Prototype with constant bindings" https://www.hackingwithswift.com/quick-start/swiftui/swiftui-tips-and-tricks

import SwiftUI

typealias OnTabHandler = (String) -> Void

struct PassingFunc: View {
    @State var showSheet = false

    var onTabHandler: OnTabHandler = { text in
        print(text)
    }

    var body: some View{
        VStack{
            // print to console
            ChildView(text: "Hello - Console", showSheet:$showSheet, onTabHandler: onTabHandler)

            // show sheet
            ChildView(text: "Hello - Present"
                , showSheet:$showSheet, onTabHandler: {_ in
                self.showSheet = true}
            )
                .sheet(isPresented:$showSheet){ Text("sheet view")}
        }
    }
}

struct ChildView:View{
    var text:String
    @Binding var showSheet: Bool
    var onTabHandler:OnTabHandler

    var body: some View{
        Button("Tab Me"){
            self.onTabHandler(self.text)
        }
    }
}

Upvotes: 2

Asperi
Asperi

Reputation: 258355

It is struct, you cannot use self in such case, because it would be actually trying to copy value which construction is not finished yet... instead you can use binding directly because binding actually a holder of reference, so correct & worked approach in your case is

self.onTabHandler = {_ in

    showSheet.wrappedValue = true
}

Upvotes: 2

Related Questions