@escaping
is infectious to all calling methods, and the compiler determines when you must include it.
Consider this example (which compiles):
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: ()->()) {
dispatchNow(block)
}
func dispatchNow(_ block: ()->()) {
block()
}
This modified example, however, produces two errors of type non-escaping parameter may allow it to escape
:
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: ()->()) {
dispatchLater(block)
}
func dispatchLater(_ block: ()->()) {
DispatchQueue.main.async(execute: block)
}
The dispatch on main means the dispatchLater
method needs @escaping
, and once you've added that, the dispatchSometime
method also requires @escaping
for the example to compile.
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: @escaping ()->()) {
dispatchLater(block)
}
func dispatchLater(_ block: @escaping ()->()) {
DispatchQueue.main.async(execute: block)
}
However, the take away is just:
- Keep adding
@escaping
up the call chain until the compiler stops complaining.
- The keyword doesn't change anything: it's a warning which says, essentially, "be careful to use
weak
with captured variables as they may be retained along with the block itself."
Implications
The really fun case with this is where you have to adjust several methods to include the @escaping
keyword, which gets the compiler to stop complaining. However, if those methods are actually conforming to a protocol, that protocol's methods must also get the @escaping
keyword, which also infects all other protocol conformants. Fun!