It is possible for a closure to be called after the function it was passed into returns. This is called an escaping closure and is wrapped with the @escaping
keyword. This is common when a function takes a closure, performs a long-running operation (e.g. a network request), and calls the closure after the function has returned. Closures also escape when they are assigned to a variable to be used later on. The closure may be called long after the calling function returns. Swift needs to hold a reference to the closure in this case which is accomplished with the @escaping
keyword. Let’s take a look at an example:
struct Recipe { let ingredientAdder: (String) -> Void init(ingredientAdder: (String) -> Void) { //ERROR self.ingredientAdder = ingredientAdder } }
Above we have a struct
named Recipe
that takes a closure in its initializer. Within the initializer, we assign it to a constant named ingredientAdder
on the Recipe
struct. This will not compile because we hold a reference to the closure via ingredientAdder
which can be called at some point in the future. To fix this we wrap the closure with @escaping
to tell the compiler to hold a reference to the closure for later use.
struct Recipe { let ingredientAdder: (String) -> Void init(ingredientAdder: @escaping (String) -> Void) { self.ingredientAdder = ingredientAdder } }
Instructions
In Escaping.swift, we have a NumberPrinter
struct that holds onto some closures for execution later. Add the @escaping
keyword to the closures that require it.