What's a good example of an escape closure in Swift?
An example of an escaping closure would be the completion handler in some asynchronous task, such as initiating a network request:
func performRequest(parameters: [String: String], completionHandler: @escaping (Result<Data, Error>) -> Void) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try! JSONEncoder().encode(parameters)
let task = URLSession.shared.dataTask(with: request) { data, _, error in
guard let data = data else {
completionHandler(.failure(error!))
return
}
completionHandler(.success(data))
}
task.resume()
}
And this is called like so:
performRequest(parameters: ["foo" : "bar"]) { result in
switch result {
case .failure(let error):
print(error)
case .success(let data):
// now use data here
}
}
// Note: The `completionHandler` above runs asynchronously, so we
// get here before the closure is called, so don't try to do anything
// here with `data` or `error`. Any processing of those two variables
// must be put _inside_ the closure above.
This completionHandler
closure is defined as @escaping
because URLSession
method dataTask
runs asynchronously (i.e. it returns immediately and its own closure will be called later when the request finishes).
In Swift 3 closure parameters become non-escaping by default.
We need to write @escaping
closure attribute before the parameters type to indicate the closure is called after the function returns.
typealias Operation = (Data?) -> ()
func addToQueue(data: Data?, operation: @escaping Operation) {
OperationQueue.main.addOperation {
operation(data)
}
}
If we remove @escaping
attribute, Xcode will show the error message below