Understanding the concept behind closures escaping and non-escaping can be very easy to understand. When a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping. The term escape is well put because it literally means that.

func request(_ endPoint: EndPoint, then handler: @escaping (Result<Data,Error>) -> Void) {

    let task = urlSession.dataTask(with: endPoint.url) {
       data, response, error in

        if let error = error {
            handler(.failure(error))
        } else if let data = data {
            handler(.success(data))
        }
    }

    task.resume()
}

In the example above the closure handler is called after the function returns as the method request(_, then:) is asynchronous.

By default closures are marked as non-escaping. The benefits are the performance and the ability for the compiler to optimize the code. If the compiler knows that a closure is non-escaping, it can take care of the details related to memory management.

func requests(_ endPoint: EndPoint, then handler: (Result<Data,Error>) -> Void) {

    handler(.success(Data()))
}

Marking a closure by default as non-escaping also means that the self keyword can used without issues as the closure is invoked before the function returns. There is no need to use a weak reference to self in the closure.

Thanks for reading! ?