Почему для опционального замыкания в Swift не требуется указывать @escaping?

«Почему для опционального замыкания в Swift не требуется указывать @escaping?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Опциональное замыкание (() -> Void)? по умолчанию считается escaping. Явное указание @escaping не требуется, потому что сама опциональная природа (Optional) подразумевает, что замыкание может быть сохранено и вызвано позже, выходя за рамки текущего контекста функции.

Причина: Тип Optional — это перечисление (enum), которое может хранить значение (в данном случае замыкание) как ассоциированный параметр. Поскольку это значение может быть сохранено (например, в свойстве) и использовано асинхронно, компилятор Swift автоматически трактует его как escaping.

Пример:

func performAsyncAction(completion: (() -> Void)?) {
    // Замыкание передаётся в асинхронный контекст -> оно escaping.
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        completion?() // Вызов может произойти после выхода из функции.
    }
}

Контраст с non-escaping: Неопциональные параметры-замыкания по умолчанию non-escaping. Они гарантированно выполняются до выхода из функции, что позволяет компилятору проводить оптимизации.