swiftswiftuiclosuresswift-optionals

What is the correct way to declare, instantiate and unwrap an optional closure?


I have a class CommentView that has an optional closure (for simplification purposes, I've cut down the code to its bare basics to make it easy for the reader):

struct CommentView: View
{
    @State var enterButtonPushed: ((Comment)  -> Void)?

    init(enterButtonPushed: @escaping (Comment) -> Void)
    {
        self.enterButtonPushed = enterButtonPushed
    }
    
    var body: some View
    {
        Button("Enter")
        {
            if let enterButtonPushed = self.enterButtonPushed
            {
                enterButtonPushed(Comment())
            }
            else
            {
               print("EnterButtonPushed is nil")
            }
        }
        .buttonStyle(.borderedProminent)
    }
}

A CommentView class is created correctly from another class:

    CommentView 
    {
        comment in self.reader.comments.append(comment)
    }

When I push the enter button, the print statement is indicating that the closure is nil, even though I clearly initialized it with a value. What is the correct way syntactically to declare, instantiate and unwrap an optional closure?


Solution

  • The closure is passed from outside the view, so it should not be a @State. @States are things that are "internal" to the view, and this is why it is often said that @State should always be private.

    Just make it a let, and since the initialiser doesn't take an optional closure, it doesn't need to be optional, and you don't need to unwrap it.

    let enterButtonPushed: (Comment) -> Void
    

    If you would like it to be optional, that's fine too, and the way you are unwrapping it is correct.

    As for why enterButtonPushed is not set, even when you did set it in init, this is because @State is a property wrapper. Setting enterButtonPushed this way is just syntactic sugar for setting the property wrapper's wrappedValue. And the setter of wrappedValue can totally just do nothing, because you are using @State incorrectly.