CosmicCat
CosmicCat

Reputation: 622

Question about extra closures in Alert() call (SwiftUI)

I am a little rusty on Swift since its a new language for me, I am not new to closures however due to some past experiences with Javascript. I am very familiar and comfortable with alert calls but recently ran into a problem, where I wanted to execute a function after the alert is dismissed. I found a solution, but was confused on why a programmer is allowed to simply open a closure right before the closing bracket in an alert call, or any struct call in that matter.

.alert(isPresented: $bindingVariable) {
            Alert(title: Text("Title"), message: Text("Message"), dismissButton: .default(Text("Continue")) {
                //this closure is where my confusion lies
                self.functionCall()
            })
        }

I was wondering if someone would kindly link me to a document or explain the significance behind this reasoning as I can't tell if this is a SwiftUI quirk or simply a lapse in my own closure knowledge. Alternative solutions are welcome too!

-Thank you all

Upvotes: 1

Views: 264

Answers (1)

Craig Temple
Craig Temple

Reputation: 545

It can definitely be a bit confusing at first!

Xcode's option key is your friend. Option-click just about anything to view the documentation or declaration.

Let's break it down. First, let's simplify this:

Alert(title: Text("Title"), message: Text("Message"), dismissButton: .default(Text("Continue")) {
    //this closure is where my confusion lies
    self.functionCall()
})

To this:

let alertButton: Alert.Button()
Alert(title: Text("Title"), message: Text("Message"), dismissButton: alertButton)

That's all that's happening there. But you've got the dismissButton paramater value coded directly into the Alert.

Of course the stub above with the let constant is not going to work, because we haven't initialized the Alert.Button.

What your code did is call Alert.Button's .default() static function to return an initialized Alert.Button.

And Alert.Button.default() takes a few parameters. Here's the documentation you get when you Option-Click the .default method:

enter image description here

That should look a lot like a plain old Button(). And what do buttons have? A label and an action when you click it.

So that extra closure you're seeing is actually the buttons's action closure.

And of course just like everywhere else in Swift, because the Alert.Button.default() method's final parameter (action in this case) is a closure, you can specify it outside the parentheses of the .default() method call.

So you've got the .default() function being called with a trailing closure, and then passed into the Alert()'s dismissButton parameter.

If you broke it out, it would look like so:

let alertButton = Alert.Button().default(Text("Continue")) {
    //this closure is where my confusion lies
    self.functionCall()
}

Alert(title: Text("Title"), message: Text("Message"), dismissButton: alertButton)

In the code you posted, the .default() call happens to be coded inline into the Alert() initialization parameters. Hence parentheses around the function call with the trailing closure:

Alert( ... dismissButton: .default(...) {...})

Does that make sense?

Upvotes: 1

Related Questions