Closure Use of Non-Escaping Parameter - Swift 3 Issue

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.

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) -> ()) -> ()

Trouble with non-escaping closures in Swift 3

As already said, Optional closures are escaping. An addition though:

Swift 3.1 has a withoutActuallyEscaping helper function that can be useful here. It marks a closure escaping only for its use inside a passed closure, so that you don't have to expose the escaping attribute to the function signature.

Can be used like this:

extension Array {

private func someFunction(someClosure: (() -> Int)?) {
someClosure?()
}

func someOtherFunction(someOtherClosure: () -> Int) {
withoutActuallyEscaping(someOtherClosure) {
someFunction(someClosure: $0)
}
}
}

let x = [1, 2, 3]

x.someOtherFunction(someOtherClosure: { return 1 })

Hope this is helpful!

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()

}
}

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) -> ()

Capturing closures within closures: Xcode throws error: Escaping closure captures non-escaping parameter

The following compiles fine in Swift 5.4:

import UIKit
class NestedCallback {
let callback: (String, @escaping () -> Void) -> Void
public init(callback: @escaping ((String, @escaping () -> Void) -> Void)) {
self.callback = callback
}
}

NestedCallback(callback: { first, second in
let url = URL(string: "https://testapi.com")!
URLSession.init().dataTask(with: url) { data, response, error in
second()
}
})

Swift-3: closure with escaping and non-escaping behaviour together

The rule for when you need @escaping is simple – if a closure function argument can escape the lifetime of the function call, it needs to be marked as @escaping (the compiler simply won't let you compile it otherwise).

In your example code, completionHandler is not marked as @escaping in f2 – therefore it cannot escape the lifetime of f2. Therefore it cannot possibly escape the lifetime of f1 either, thus you don't need to mark f1's completionHandler as @escaping.

If however, f2's completionHandler could escape the lifetime of f2, then you would have to mark both f2 and f1's parameters as @escaping as it could escape the lifetime of both calls.



Related Topics



Leave a reply



Submit