@noescape attribute in Swift 1.2
@noescape
can be used like this:
func doIt(code: @noescape () -> ()) {
/* what we CAN */
// just call it
code()
// pass it to another function as another `@noescape` parameter
doItMore(code)
// capture it in another `@noescape` closure
doItMore {
code()
}
/* what we CANNOT do *****
// pass it as a non-`@noescape` parameter
dispatch_async(dispatch_get_main_queue(), code)
// store it
let _code:() -> () = code
// capture it in another non-`@noescape` closure
let __code = { code() }
*/
}
func doItMore(code: @noescape () -> ()) {}
Adding @noescape
guarantees that the closure will not be stored somewhere, used at a later time, or used asynchronously.
From the caller's point of view, there is no need to care about the lifetime of captured variables, as they are used within the called function or not at all. And as a bonus, we can use an implicit self
, saving us from typing self.
.
func doIt(code: @noescape () -> ()) {
code()
}
class Bar {
var i = 0
func some() {
doIt {
println(i)
// ^ we don't need `self.` anymore!
}
}
}
let bar = Bar()
bar.some() // -> outputs 0
Also, from the compiler's point of view (as documented in release notes):
This enables some minor performance optimizations.
Why is not @noescape automatically applied to Swift closures when it is needed?
Edit: Swift 3 makes a few changes here:
- Non-escaping closures are the default. Now you don't have to apply
@noescape
to your function declarations that take closures as parameters if you want to require non-escaping closures. (Instead, you have to apply@escaping
in cases where you do plan to store a closure past the return of your function.) - The "escaping-ness" of a closure is now part of the function type declaration. So instead of a parameter that looks like
@escaping completionHandler: (Bool, Error) -> Void
, it'scompletionHandler: @escaping (Bool, Error) -> Void
.
It's kinda hard to rewrite my whole answer to reflect that, so I'll leave it here for now... read on for the whys behind escaping-ness, just remember to invert noescape/escaping declarations. :) Or read about Escaping Closures in the Swift 3 version of The Swift Programming Language.
@noescape
isn't just a hint for compiler optimizations; it's part of the interface that a function declaration presents to callers. Whether a parameter to a function is declared @noescape
or allows escaping closures changes how a caller of that function writes the closure they pass as the parameter.
For example, given the function (from SequenceType
):
func filter(@noescape includeElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]
If I wanted to filter a collection based on some criteria that requires calling a method on self
, I know I can safely do that without worrying about whether the closure will capture self
and create a retain cycle.
// horribly contrived example
class Foo {
var things: [Thing]
func isCurrentlyAwesomeThing(thing: Thing) -> Bool { /*...*/ }
func thingsThatAreAwesomeRightNow() -> [Thing] {
return things.filter {
return isCurrentlyAwesomeThing($0)
}
}
}
If filter
permitted an escaping closure, the closure that calls isCurrentlyAwesomeThing()
would capture self
. (And thus require that method to be called with an explicit self.
prefix.) And if the implementation of filter
actually saved the closure beyond the runtime of that function, there'd be a memory leak because the closure retains self
and self
retains the array whose filter
function received the closure.
When you call a function whose closure parameters aren't declared @noescape
, you have to account for that possibility. This is why you see calls that add a [weak self]
capture list and a strong redeclaration inside the closure to make sure self
doesn't get deallocated during the closure. (Or at least an [unowned self]
in cases where you're reasonably certain the closure won't persist longer than self
.)
If closure parameters weren't able to be decorated as @noescape
(or as non-escaping through the absence of that decorator), you wouldn't know when calling a function that takes a closure whether you have to be careful about what that closure captures.
How to add @noescape annotation to optional closure
Requirements
If your requirements are the following:
- the
baz
param is aclosure
- the
baz
param is marked with@noescape
(because you want to omitself
in the closure code) - the
baz
param can be omitted during the invocation offoo
Solution
Then you can use the following syntax
func foo(bar: String, @noescape baz: ((String) -> ()) = { _ in } ) {
}
As you can see the main difference from your code is that:
- here
baz
is not anoptional type
(but it's an "optional parameter") - and its default value is an
empty closure
not anil
value.
Examples
As you requested you can now pass a closure to baz
without the need of using self
class Boo {
let world = "world"
func boo() {
foo("hello") { (something) -> () in
print(world)
}
}
}
And you can also omit the baz
param
class Boo {
let world = "world"
func boo() {
foo("hello")
}
}
Update: using a closure with return type different from Void
In a comment below users TadeasKriz
asked about how to use this approach with a closure having the return value different the Void
.
Here it is the solution
func foo(bar: String, @noescape baz: ((String) -> (Int)) = { _ in return 0 } ) {
}
Here the baz
param does required a closure with 1 param of type String
and a return value of type Int
.
As you can see I added a default value to the param, a closure that does return 0
. Please note that the default closure will never be used so you can replace 0
with any Int
value you want.
Now you can decide whether to use pass your closure to the baz
param
class Boo {
let world = "world"
func boo() {
foo("hello") { (something) -> Int in
print(world)
return 100
}
}
}
Or, again, you can totally omit the baz
param.
class Boo {
let world = "world"
func boo() {
foo("hello")
}
}
Why does Swift 1.2 reduce force me to use the combine: argument name?
I filed a bug report on this, and Apple replied that the change was intentional. In my view, being able to say reduce(0,+)
was elegant and pithy, so the API for reduce
should declare the external parameter name unnecessary. In Apple's stated view, the combine:
external parameter name clarifies the purpose of the parameter. We have agreed to disagree.
Swift 1.2 - Error caused by closure parameters of a class function
This seems to be a bug in Swift 1.2 (and even Swift 2 (Xcode 7 beta 3)) with single parameter closures with external names.
As workaround you can remove the external parameter name "u":
internal class func closureFunc(#arg: T, worker: (first: T, second: String) -> U, closure: (U -> Void)?) -> Void
in Swift 2 (only) there is another workaround where you can give the passed closure an external name (since this would conform to the new and more strict naming conventions):
Test.closureFunc(arg: "", worker: { (first, second) -> Void in
//code
}) { (anyExternalNameWorks u: Void) -> Void in
//code
}
Create a forCount control structure in Swift
There are no preprocessor macros in Swift, but you can define a global function taking the iteration count and a closure as arguments:
func forCount(count : Int, @noescape block : () -> ()) {
for _ in 0 ..< count {
block()
}
}
With the "trailing closure syntax", it looks like a built-in
control statement:
forCount(40) {
print("*")
}
The @noescape
attribute allows the compile to make some optimizations
and to refer to instance variables without using self
, see
@noescape attribute in Swift 1.2 for more information.
As of Swift 3, "noescape" is the default attribute for function
parameters:
func forCount(_ count: Int, block: () -> ()) {
for _ in 0 ..< count {
block()
}
}
This is one thing I do not understand in Swift
This was the only form I was able to type this without Xcode complaining. If this is correct, what is the purpose of this
->Void
there? What could this possibly returning?
It is the same as in your typealias
, in Swift a function type has the form:
(parameter definitions) -> return type
and functions which return nothing have a return type of Void
(similar to C). The full form off a closure expression is:
{ (
parameter definitions) ->
return typein
body}
Without any inference this expression provides the full type of the closure, and the -> Void
Return type in your example specifies that your closure returns nothing. In your assignment this full type will be checked at compile time to conform to the type of onClick
.
Now Swift will infer lots of stuff and there are various shorthands available for closure expressions, you will find that Swift accepts:
button.onClick = { textField in }
as well here with both the argument and return types of the closure being inferred.
By the way, as a bonus, [...] any ideas?
Just make the types match:
func doSomething(textField : NSTextfieldSuper) { }
button.onClick = doSomething
Unlike in (Objective-)C functions and closures (blocks in C) are interchangeable (as they are in plenty of other languages, C is the oddfellow here)
HTH
Related Topics
Swap Rootviewcontroller With Animation
Reference to Property in Closure Requires Explicit 'Self.' to Make Capture Semantics Explicit
Println Dictionary Has "Optional"
Swift: Print Decimal Precision of Division
Do Swift Inner Classes Have Access to Self of Outer Class
Expected to Decode Array<Any> But Found a Dictionary Instead
Checking for Nil Value in Swift Dictionary Extension
How to Generate Large, Ranged Random Numbers in Swift
Distinction in Swift Between Uppercase "Self" and Lowercase "Self"
Generating Random Numbers With Swift
Ios11 Swift Silent Push (Background Fetch, Didreceiveremotenotification) Is Not Working Anymore
Nsfontattributedstring Worked Before Xcode 6.1
How to Load an Image from Documents Directory on MACos Swift
Any Way to Iterate a Tuple in Swift
How to Create an Instance of a Class from a String in Swift