@Noescape attribute in Swift 1.2

In Swift 1.2 there is a new attribute with closing parameters in functions, and the documentation says:

This means that the parameter is only ever called (or passed as @ noescape in the call), which means that it cannot extend the life of the call.

In my understanding, before that we could use [weak self] to prevent the closure from having a strong reference, for example, its class and self can be nil or an instance when the closure is done, but now @noescape means that the closure will never done if the class is de-initialized. Do I understand correctly?

And if I'm right, why use @noescape closure for a regular function when they behave very similarly?

+74
closures swift attributes
Feb 10 '15 at 8:51
source share
3 answers

@noescape can be used as follows:

 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 ensures that the closure will not be stored anywhere, used later or used asynchronously.

From the perspective of the caller, there is no need to take care of the lifetime of the captured variables, since they are used in the called function or none at all. And as a bonus, we can use 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 a compiler point of view (as described in the release notes ):

This allows you to optimize performance a bit.

+143
Feb 10 '15 at 9:47
source share

One way to think about this is that each variable inside the @noescape block should not be strong (and not just itself).

Optimization is also possible, because after allocating a variable, which then ends in a block, it cannot simply be freed at the end of the function. Therefore, it must be heaped and use ARC to deconstruct. In Objective-C, you need to use the "__block" keyword to ensure that the variable is created in a friendly block. Swift will automatically detect that the keyword is not required, but the cost is the same.

If variables are passed to the @nosecape block, they can be stack variables and do not need ARC to free.

Now, variables do not even need a null reference to weak variables (which are more expensive than unsafe pointers), since they are guaranteed to be "alive" for the life of the block.

All this leads to a faster and more optimal code. And reduces the overhead for using @autoclosure blocks (which are very useful).

+28
Feb 10 '15 at 20:33
source share

(Regarding Michael Gray's answer above).

Not sure if this is specifically documented for Swift, or even the Swift compiler makes full use of it. But the standard compiler project allocates storage for the instance on the stack, if the compiler knows the called function, will not try to keep the pointer to this instance on the heap and throw a compile-time error if the function tries to do this.

This is especially useful when passing non-scalar value types (for example, enumerations, structures, closures), since copying them is potentially much more expensive than just passing a pointer to the stack. Allocating an instance is also significantly cheaper (one instruction against calling malloc ()). So this is a double win if the compiler can do this optimization.

Again, does this version of the Swift compiler really have to be announced by the Swift team, or will you have to read the source code when they are open source. From the “minor optimization” quote above, it sounds like it’s not, or the Swift team considers it “minor”. I would consider this a significant optimization.

Presumably, the attribute exists so that (at least in the future) the compiler will be able to perform this optimization.

+8
Oct 24 '15 at 20:31
source share



All Articles