How to Call Non-Escaping Closure Inside a Local Closure

How to call non-escaping closure inside a local closure?

Non-parameter closures are @escaping, by default

"If localClosure is, by default, non-escaping, then why ..."

Based on the discussion in the comments below (thanks @Hamish), we can state the following facts regarding non-parameter closures in Swift 3.0:

  • They are, contrary to what one might believe, @escaping, by default. As @noescape is deprecated in Swift 3 (see e.g. Xcode 8 release notes or Swift evolution proposal SE-0103), this means that non-parameter closures cannot be made non-escaping without making use of deprecated methods.
  • As described in the following evolution thread, the lack of @noescape attribute for non-parameter closures is a missing feature (somewhat of a regression as this was not a limitation in Swift 2.2), but one that is not necessarily to be implemented in the future (if I'm to understand the answer by Apple dev. Jordan Rose in the linked evolution thread).
  • We may however (still) apply the deprecated @noescape attribute to a non-parameter closure to make it non-escaping, but will then notably be prompted with an incorrect warning (as below, emphasis mine), which has now been reported as a bug by @Hamish, see bug report SR-2969.

    "@noescape is default and is deprecated"

To summarize, localClosure is @escaping, which naturally means it cannot be allowed to wrap the non-escaping closure parameter closure of test(...).


[†] By non-parameter closures, I refer to all closures that are not parameters to a function, i.e., closures that are not supplied to a function as an argument.


As a side-note, which you possibly already knows given your question: we may naturally mark closure as @escaping if we'd wish to process/wrap it as in your example.

func test(closure: @escaping () -> ()) -> () -> () {
let escapingLocalClosure = { closure() }
return escapingLocalClosure
}

Closure use of non-escaping parameter - Swift 3 issue

updateCompleted is of type (_ completed: @escaping UpdateInProgressCompletion) -> (), which as it's a function parameter itself, means that it is non-escaping by default (note that 'non-escaping by default' behaviour is only applicable to function closure arguments, see this Q&A, as well as its dupe target on the topic).

Therefore in order to allow updateCompleted to escape, you need to mark (_ completed: @escaping UpdateInProgressCompletion) -> () as @escaping in your typealias:

typealias UpdateInProgressHandler = (@escaping (_ completed: @escaping UpdateInProgressCompletion) -> ()) -> ()

Swift: Escaping closure captures non-escaping parameter 'onCompletion'

You have to mark both completion handlers with @escaping. Usually the compiler offers a fix

class RestApiManager: NSObject {
static let sharedInstance = RestApiManager()

let baseURL = "http://api.randomuser.me/"

func getRandomUser(onCompletion : @escaping (JSON) -> Void) {
makeHTTPGetRequest(path: baseURL, onCompletion: { json, err -> Void in
onCompletion(json)
})
}

func makeHTTPGetRequest(path: String, onCompletion: @escaping ServiceResponse) {
let request = NSMutableURLRequest(url : URL(string: path)! as URL)

let session = URLSession.shared

let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
let json:JSON = JSON(data as Any)
onCompletion(json, error as NSError?)
})
task.resume()

}
}

Closure use of non-escaping parameter may allow it to escape

This is due to a change in the default behaviour for parameters of function type. Prior to Swift 3 (specifically the build that ships with Xcode 8 beta 6), they would default to being escaping – you would have to mark them @noescape in order to prevent them from being stored or captured, which guarantees they won't outlive the duration of the function call.

However, now @noescape is the default for function-typed parameters. If you want to store or capture such functions, you now need to mark them @escaping:

protocol DataServiceType {
func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)
func cachedData(location: String) -> Data?
}

func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void) {
// ...
}

See the Swift Evolution proposal for more info about this change.

Escaping Closures in Swift

Consider this class:

class A {
var closure: (() -> Void)?
func someMethod(closure: @escaping () -> Void) {
self.closure = closure
}
}

someMethod assigns the closure passed in, to a property in the class.

Now here comes another class:

class B {
var number = 0
var a: A = A()
func anotherMethod() {
a.someMethod { self.number = 10 }
}
}

If I call anotherMethod, the closure { self.number = 10 } will be stored in the instance of A. Since self is captured in the closure, the instance of A will also hold a strong reference to it.

That's basically an example of an escaped closure!

You are probably wondering, "what? So where did the closure escaped from, and to?"

The closure escapes from the scope of the method, to the scope of the class. And it can be called later, even on another thread! This could cause problems if not handled properly.

By default, Swift doesn't allow closures to escape. You have to add @escaping to the closure type to tell the compiler "Please allow this closure to escape". If we remove @escaping:

class A {
var closure: (() -> Void)?
func someMethod(closure: () -> Void) {
}
}

and try to write self.closure = closure, it doesn't compile!

swift Parameter is implicitly non-escaping

The error is shown because 'b' and 'f' do have different signatures.

'b' is an escaping closure 'f' is not.

when doing:

let a = f

you are copying 'f'. The signature stays the same "nonescaping () -> ()".

Declaring a closure in function definition gives you implicit 'nonescaping' in body gives you implicit 'escaping'.

Decorating your closure in the header with @escaping will solve the problem.

func test(f: @escaping () -> ()) {

If you want to know more:
https://medium.com/swiftcommmunity/what-do-mean-escaping-and-nonescaping-closures-in-swift-d404d721f39d

Why do closures require an explicit `self` when they're all non-escaping by default in Swift 3?

In Swift 3, all closures are non-escaping by default

No, in Swift 3, only closure function arguments (i.e function inputs that are functions themselves) are non-escaping by default (as per SE-0103). For example:

class A {

let n = 5
var bar : () -> Void = {}

func foo(_ closure: () -> Void) {
bar = closure // As closure is non-escaping, it is illegal to store it.
}

func baz() {
foo {
// no explict 'self.' required in order to capture n,
// as foo's closure argument is non-escaping,
// therefore n is guaranteed to only be captured for the lifetime of foo(_:)
print(n)
}
}
}

As closure in the above example is non-escaping, it is prohibited from being stored or captured, thus limiting its lifetime to the lifetime of the function foo(_:). This therefore means that any values it captures are guaranteed to not remain captured after the function exits – meaning that you don’t need to worry about problems that can occur with capturing, such as retain cycles.

However, a closure stored property (such as bar in the above example) is by definition escaping (it would be nonsensical to mark it with @noescape) as its lifetime not limited to a given function – it (and therefore all its captured variables) will remain in memory as long as the given instance remains in memory. This can therefore easily lead to problems such as retain cycles, which is why you need to use an explicit self. in order to make the capturing semantics explicit.

In fact, case in point, your example code will create a retain cycle upon viewDidLoad() being called, as someClosure strongly captures self, and self strongly references someClosure, as it's a stored property.

It's worth noting that as an extension of the "stored function properties are always escaping" rule, functions stored in aggregates (i.e structures and enumerations with associated values) are also always escaping, as there's no restrictions on what you do with such aggregates. As pointed out by pandaren codemaster, this currently includes Optional – meaning that Optional<() -> Void> (aka. (() -> Void)?) is always escaping. The compiler might eventually make this a special case for function parameters though, given that optional is already built on a lot of compiler magic.


Of course, one place where you would expect to be able to use the @noescape attribute is on a closure that’s a local variable in a function. Such a closure would have a predictable lifetime, as long as it isn’t stored outside of the function, or captured. For example:

class A {

let n = 5

func foo() {

let f : @noescape () -> Void = {
print(n)
}

f()
}
}

Unfortunately, as @noescape is being removed in Swift 3, this won't be possible (What's interesting is that in Xcode 8 GM, it is possible, but yields a deprecation warning). As Jon Shier says, we’ll have to wait for it to be re-added to the language, which may or may not happen.

Is there a way to nullify a escaping closure without calling it?

In your example, the closure is in fact not escaping, since you're not assigning it to anything outside the function, so there's no need to nullify:

func should(completion: () -> Void) {
if !something {
completion()
}
}

But if it was escaping, say by assigning it to a property, then you could nullify the property to release it:

class Foo {
let fn: (() -> Void)?

func should(completion: @escaping () -> Void) {
fn = completion
}

func executeAndRelease() {
fn?()
fn = nil
}
}

Escaping Closure captures non-escaping parameter dispatch

As closures documentation states:

A closure is said to escape a function when the closure is passed as
an argument to the function, but is called after the function returns.
When you declare a function that takes a closure as one of its
parameters, you can write @escaping before the parameter’s type to
indicate that the closure is allowed to escape.

By default a closure is nonescaping like your dispatch parameter, but you are calling it inside an escaping closure which probably is the closure that you pass as a parameter in getMovies function.

The solution is simple, just add @escaping before the dispatch parameter type:

typealias ActionCreator = (_ dispatch: @escaping (Action) -> (), _ getState: () -> AppState) -> ()

Swift @escaping and Completion Handler

Swift Completion Handler Escaping & Non-Escaping:

Assume the user is updating an app while using it. You definitely want
to notify the user when it is done. You possibly want to pop up a box
that says, “Congratulations, now, you may fully enjoy!”

So, how do you run a block of code only after the download has been
completed? Further, how do you animate certain objects only after a
view controller has been moved to the next? Well, we are going to find
out how to design one like a boss.

Based on my expansive vocabulary list, completion handlers stand for

Do stuff when things have been done

Bob’s post provides clarity about completion handlers (from a developer point of view it exactly defines what we need to understand).

@escaping closures:

When one passes a closure in function arguments, using it after the function’s body gets executed and returns the compiler back. When the function ends, the scope of the passed closure exist and have existence in memory, till the closure gets executed.

There are several ways to escaping the closure in containing function:

  • Storage: When you need to store the closure in the global variable, property or any other storage that exist in the memory past of the calling function get executed and return the compiler back.

  • Asynchronous execution: When you are executing the closure asynchronously on despatch queue, the queue will hold the closure in memory for you, can be used in future. In this case you have no idea when the closure will get executed.

When you try to use the closure in these scenarios the Swift compiler will show the error:

error screenshot

For more clarity about this topic you can check out this post on Medium.

Adding one more points , which every ios developer needs to understand :

  1. Escaping Closure : 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.
  2. Non-escaping closure : A closure that’s called within the function it was passed into, i.e. before it returns.


Related Topics



Leave a reply



Submit