I am converting code to Swift using Xcode 8, but compiler warns to add #escape in some of the nested functions already created in Swift 2.3, with closure syntax. I have found some other keywords also #noescape and #autoclosure, but I have some question regarding this :
What is functional need of this keyword?
What is impact of writing #escaping ?
Is it necessary to write ?
Is #autoclosure behave same as #escape?
When to use which keyword and why ?
Here is Swift-evolution document, but not getting much from it.
The most important difference is between #escaping and #noescaping (there is no such keyword in Swift 3!). When a closure is marked as #noescape, you can be sure that the closure won't be retained by the method (e.g. to perform an asynchronous call), therefore you don't have to worry about ownership cycles (there are some other minor benefits).
#escaping closures can be saved or called sometimes in the future therefore you have to be sure to handle ownership (e.g. [weak self]) correctly.
For #autoclosure see How to use Swift #autoclosure . In short, it allows you to skip braces around the closure in some situations.
The default (when not specified) is #noescaping in Swift 3 (see rationale). They keyword does not actually exist anymore. There is only #escaping.
#escape means that your function can be called after method ends.
#noescape means that your closure will be called before the end of function it passed to.
#autoclosure means that you can omit writing closure braces, but it automatically becomes #noescape.
#autoclosure creates an automatic closure around the expression. So when the caller writes an expression like 2 > 1, it's automatically wrapped into a closure to become {2 > 1} before it is passed to some function.
2 - Easier for compiler to perform optimisations.
3 - beter to write, to give compiler(or anybody that using your function) information how it behaves with your closure
4 - no
5 - described on the top of the answer
Related
This question already has answers here:
Shall we always use [unowned self] inside closure in Swift
(11 answers)
Closed 3 years ago.
According to https://stackoverflow.com/a/38144190/72437
The reason is that the immediately applied closure {}() is considered
#noescape. It does not retain the captured self.
and https://oleb.net/blog/2016/10/optional-non-escaping-closures/
However, it’s impossible to create a reference cycle with a
non-escaping closure — the compiler can guarantee that the closure
will have released all objects it captured by the time the function
returns.
However, I still do not understand why #nonescaping closure does not retain self, and doesn't require [weak self]? Can someone explain this concept in simpler manner?
The closure does not need to retain self, because the closure itself only lives as long as the function that created it (and self won't go away as long as one of its own functions is still running). So there is no need to keep anything around for longer than the function invocation itself.
You only need to retain something in order to make sure it exists for (at least) as long as you yourself exist (or need access to that thing).
If the closure was escaping the scope of the function that created it, then it could not rely on any of the things it got from that function's scope being kept alive after the function returned. So it has to retain these things itself.
A non-escape closure tells the complier that the closure you pass in will be executed within the body of that function so do not need to use weak self.
This question already has answers here:
Swift function object wrapper in apple/swift
(1 answer)
How are escaping closures implemented in Swift 3 (under the hood)? Are they implicitly block_copied/retained like in objective-c?
(1 answer)
Closed 5 years ago.
I feel a bit confused, trying to understand, how #escaping closures are working.
As far as I understand
An escaping closure is a closure that’s called after the function it was passed to returns. In other words, it outlives the function it was passed to.
But how that closure is stored in the memory. Are they located in stack or in heap? How do they refer to the function it was passed? And what the key difference in comprising with #nonescaping.
Think of an escaping block as code that jumps back to where the function was called originally. Meaning, if you have this method which executes the escaping block if variable is set to "yes":
func thisMethodHasA(variable: String, withAn escaping: #escaping (()->())) {
if variable == "yes" {
escaping()
//this will execute the code in the brackets
}
//this will return the method
}
and you call it like so (in playgrounds):
thisMethodHasA(variable: "no") {
print("the bracket code is executed")
}
print("thisMethodHasNowFinished")
the printed result is:
thisMethodHasNowFinished
As you see, the code is never executed.
If we set it to "yes":
thisMethodHasA(variable: "yes") {
print("the bracket code is executed")
}
print("thisMethodHasNowFinished")
the bracket code is executed
thisMethodHasNowFinished
As you see, the code inside the brackets was run before the method ended it's course.
So really, escaping blocks are pointers to code which only allocates a potential reference of memory space for that escaping block.. but without actually allocating that space until the escaping block is called. So i would say that escaping blocks are referenced similarly to how class references are performed to minimize memory allocation. So what your referenced sentence means, is that the code in escaping blocks keep a singular pointer throughout the app cycle, unlike a method pointer, which is deallocated whenever it's run it's course. By this definition, i'd suggest that it is stored in the stack, not the heap (to address your question).
I found these links/posts and articles which seem to get to a close answer too:
https://stackoverflow.com/a/41257089/7183483
For a good read on how Swift manages both Stack and Heap allocation:
https://medium.com/#itchyankles/memory-management-in-rust-and-swift-8ecda3cdf5b7
this one also explains the logic behind alocation.. so perhaps there is some hinting here at how these blocks are managed.. again, seems to be a lack of solid documentation on this topic out there!
My brief understanding of the difference between escaping and non-escaping closures:
Escaping closures are invoked after the function returns. From what I can tell, this is similar to the way callbacks are handled in node.js — the function returns immediately, they execute asynchronously, and the result of the long-running operation inside the function is handled when the closure/completion block/callback is called.
Non-escaping closures appear to be execute synchronously, where the function itself doesn't return until the long-running operation is complete.
(Did I get that right?)
Reading the change log and justification for moving from Swift 2's #noescape to Swift 3's #escaping (in SE-0103), it appears you can asynchronously dispatch non-escaping closures.
Is this true? Possible?
Can you dispatch a non-escaping closure function asynchronously? If so, how?
Bonus points — I really want to understand why both escaping and non-escaping closures exist:
Is there a practical use-case for asynchronously dispatching a non-escaping closure in place of an escaping closure?
In the design proposal, it suggests that functional programming benefits from non-escaping (read: synchronous?) being the default. Is this true? Why?
Is there any similarity between non-escaping closures and a promise in node.js?
If I'm wrong about all of this, why not just call it #async instead of #escaping?
I can't conceive of how an asynchronously dispatched function can be non-escaping. Is there a specific statement in the proposal that suggests that?
Regarding your additional questions:
Is there a practical use-case for asynchronously dispatching a non-escaping closure in place of an escaping closure?
This shouldn't be possible, so there wouldn't be a use-case for it :)
In the design proposal, it suggests that functional programming benefits from non-escaping (read: synchronous?) being the default. Is this true? Why?
The proposal says that functional programming would benefit from having less boilerplate (i.e. having to mark all parameters as #noescape). Since functional programming usually entails many functions-as-parameters that are predominantly non-escaping, this new default allows functional-style algorithms to have cleaner, less cluttered signatures and reduces typing the the #noescape boilerplate everywhere.
Is there any similarity between non-escaping closures and a promise in node.js?
No, promises are asynchronous and would be implemented in Swift using escaping closures, not non-escaping closures.
If I'm wrong about all of this, why not just call it #async instead of #escaping?
Because they are not exactly the same concept. An escaping closure may execute synchronously, but be saved off for execution at a later time. #async describes the nature of execution, but #escaping means only that the closure will be executed after the function it was passed to returns. When an escaping closure does execute, it might do so either synchronously or asynchronously at that time.
If I have some code that takes a closure, and self is implicitly captured, can I make it cause a compiler warning? Is there some flag I can add to the compiler command for this?
Not exactly. But there is something that addresses what's presumably the reason you'd want this warning — to prevent situation where a closure capturing self can cause a retain cycle...
The potential retain cycle from capturing self in a closure comes up when the closure is passed as a parameter to a function but is used after the function returns — that is, the lifetime of the closure (and anything captured in it) "escapes" the context in which it's written. When the closure escapes, it has to be sure it still has access to the things it uses (like self and any properties or methods thereof), so we get into memory management and possible retain cycles, [weak self]/strongSelf, etc.
With #noescape, you can declare that closures passed as parameters to a function will not escape the calling context, and as such don't require the extra memory management overhead for closures that do. And the compiler can apply some other optimizations that make running your function and its closure faster.
func someFunctionWithNoescapeClosure(#noescape closure: () -> Void) {
closure()
}
Within a #noescape closure, you can then access methods/properties on self without explicitly writing self., because you're not capturing self anymore. And, once you label a parameter #noescape, if you try to do anything that would permit it to escape (say, take the closure from the parameter and assign it to a stored property), you'd get a compiler error (not just a warning).
For the full writeup from Apple, see Nonescaping Closures in The Swift Programming Language. And this post provides an alternate perspective that might explain things further.
No, the only thing I can think of which can do anything similar is linting.
SwiftLint might be able to do something like that, and if not you can probably write your own rule for just such a thing.
In tutorials it's written that functionally both are same even closure is more easier then block and its avoided the complexity of block and memory management, I've gone through many tutorials but except these I'm not getting the difference between swift's "closure" and Objective-C "block".
Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks:
“Swift closures and Objective-C blocks are compatible, so you can pass Swift closures to Objective-C methods that expect blocks. Swift closures and functions have the same type, so you can even pass the name of a Swift function.
Closures have similar capture semantics as blocks but differ in one key way: Variables are mutable rather than copied. In other words, the behavior of __block in Objective-C is the default behavior for variables in Swift.”
Slight differences. One was mentioned; variables are captured as variables, not as values. Which can be either useful or a trap. Importantly you can define a capture list in a Swift closure, so if you include self.property in the capture list, then the value of that property is captured, and not self. That also simplifies capturing weak variables.
To show an actual code example of the differences:
This does compile:
let x : #convention(swift) (inout Int) -> ()
This does not:
let y : #convention(block) (inout Int) -> ()
with the error (inout Int) -> () is not representable in Objective-C