What Is Trailing Closure Syntax in Swift

Super simple trailing closure syntax in Swift

Here is your example fixed:

func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
print("we do something here and then go back")

// don't forget to call the closure
closure()
}


print("about to call function")

// call the function using trailing closure syntax
someFunctionThatTakesAClosure() {
print("we did what was in the function and can now do something else")
}

print("after calling function")

Output:

about to call function
we do something here and then go back
we did what was in the function and can now do something else
after calling function

What is the correct way to write multiple trailing closures in Swift?

Multiple trailing closures are a new Swift 5.3 beta feature. Your code compiles and runs correctly in Xcode 12 beta using Swift 5.3 beta, as shown in this screen shot:

Sample Image

It is probable that the environment in which you are running does not have a Swift 5.3 beta compiler.

Guard with trailing closure - Swift Syntax


Or is there a way to somehow have Xcode do autocompletion without the shortened syntax?

Xcode is quite smart. It chooses the non-trailing closure version if you do the auto completion in a control flow statement that needs a {. For example, if I type:

guard let a = reminders.first

The auto complete shows:

Sample Image

If I choose the highlighted option, I get:

guard let a = reminders.first(where: <#T##(String) throws -> Bool#>)

Sample Image

If I then press enter, I get:

guard let a = reminders.first(where: { (<#String#>) -> Bool in
<#code#>
})

Sample Image

It doesn't turn it into a trailing closure, as long as you autocomplete within a guard/if statement.

Implementing Trailing Closure Syntax In A View Modifier That Wraps Another View

Each of your item parameters is defined as (V) -> V -- this means a closure that takes V as a parameter and returns V. In fact, all you want is () -> V (a closure that takes no parameters and returns V). That gets you the trailing closure you want -- then, you can pass just the V to the view modifiers.

@available(iOS 14, *)
struct ToolbarAvailable14ViewModifier<V>: ViewModifier where V: View {
var placement: ToolbarItemPlacement
var item: V

func body(content: Content) -> some View {
content
.toolbar {
ToolbarItemGroup(placement: placement) {
item
}
}
}
}

@available(iOS 15, *)
struct ToolbarAvailable15ViewModifier<V>: ViewModifier where V: View {
var placement: ToolbarItemPlacement
var item: V

func body(content: Content) -> some View {
content
.toolbar {
ToolbarItemGroup(placement: placement) {
item
}
}
}
}

extension View {
@ViewBuilder
func toolbarIfAvailable<V>(placement: ToolbarItemPlacement, _ item: @escaping () -> V) -> some View where V: View {
if #available(iOS 14, *) {
self
.modifier(ToolbarAvailable14ViewModifier(placement: placement, item: item()))
}
if #available(iOS 15, *) {
self
.modifier(ToolbarAvailable15ViewModifier(placement: placement, item: item()))
}
else {
self
}
}
}

This also takes care of your _ in issue since the closure no longer takes an argument/parameter.

Implicit parameters in trailing closure

In

doMathOperation(4, 5, operation: multiply)

...you are being asked for a function that takes two Double parameters, and multiply is the name of just such a function, so it compiles and works.

In

doMathOperation(4, 5) { ... }

the curly braces themselves are the (body of the) function that takes two Double parameters. It makes no sense to put the name of another such function inside the curly braces.

But of course you are free to call any function you like, passing along the parameters that were passed to you; hence this works:

doMathOperation(4, 5) { multiply($0,$1) }

So, just to sum up: In the first one

doMathOperation(4, 5, operation: multiply)

there is one function, multiply, and 4 and 5 are passed to it. In the second one

doMathOperation(4, 5) { multiply($0,$1) }

there are two functions, "anonymous" (the curly braces) and multiply, and the 4 and 5 are passed into the first one and then it calls the second one.

Swift 5 Closures explained

Both are calling the same observe method. Swift has a feature called trailing closure syntax which allows you to leave off the last argument if it is a closure and have it follow the call.

So both calls to observe pass the closure as "with", and the observe method will call that closure using a call like with(snapshotValue).

See the Trailing Closures section of the Swift Documentation on Closures.

Quoting from the start of that documentation:

Trailing Closures

If you need to pass a closure expression to a function as the
function’s final argument and the closure expression is long, it can
be useful to write it as a trailing closure instead. A trailing
closure is written after the function call’s parentheses, even though
it is still an argument to the function. When you use the trailing
closure syntax, you don’t write the argument label for the closure as
part of the function call.



Related Topics



Leave a reply



Submit