Видеокурсы по изучению языка программирования Swift. Подробнее

Сбегающие замыкания

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

Когда говорят, что замыкание сбегает из функции, то это значит, что это замыкание было передано в функцию в качестве аргумента и вызывается уже после того, как функция вернулась. Когда вы объявляете функцию, которая имеет замыкание в качестве одного из параметров, то вы пишите @escaping до типа параметра, для того чтобы указать, что замыкание может сбежать

Если замыкание хранится в переменной, которая была объявлена вне функции, а затем эта переменная была передана в качестве аргумента в функцию, то получается, что замыкание, которое посредством переменной передается в функцию, сбегающее. В качестве примера можно рассмотреть функции, которые выполняют асинхронные операции в завершающем обработчике, который является замыканием.То есть получается, что функция завершает свою работу, после чего вызывается завершающий обработчик. Или другими словами обработчик не вызывается, пока не завершится работа функции, таким образом получается, что данному замыканию нужно сбежать из области работы функции, чтобы отработать позже. Например:

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
  completionHandlers.append(completionHandler)
}

Функция someFunctionWithEscapingClosure(_:) принимает и добавляет в массив замыкание, объявленное за пределами функции. Если вы не поставите маркировку @escaping, то получите ошибку компиляции.

Определяя замыкание через @escaping означает, что вы должны сослаться на self явно внутри самого замыкания. Например, в коде ниже, замыкание передается функции someFunctionWithEscapingClosure(_:) в виде сбегающего замыкания, так что вам нужно ссылаться на self внутри него явно. С другой стороны, замыкание, передаваемое в someFunctionWithNonescapingClosure(_:) является не сбегающим, значит вы можете ссылаться на self неявно.

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}
 
class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}
 
let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Выведет "200"
 
completionHandlers.first?()
print(instance.x)
// Выведет "100"
Swift: 
4.0