Оператор defer откладывает выполнение кода до выхода из текущей области видимости, обычно из функции. Удобен для очистки ресурсов, закрытия файлов и освобождения памяти — так называемый автоматизированный cleanup.
Особенности:
Пример:
func processFile() { let file = openFile() defer { closeFile(file) } // Работа с файлом // file будет закрыт даже в случае throw или return }
Нетипичное применение: частичная имитация конструкций типа 'finally', группировка кода для логирования и отслеживания времён работы.
Выполнится ли defer, если приложение завершает работу в процессе исполнения функции?
— Нет. Defer выполняется только при нормальном завершении области видимости (return, throw или нормальный выход). Если приложение аварийно завершает работу (например, из-за сигнала SIGKILL или fatalError), блоки defer не успеют выполниться.
Пример:
func foo() { defer { print("Clean up") } fatalError("Crash!") // defer не выполнится }
История
Функция, работавшая с сокетами, не очищала соединение в случае throw. Данные оставались висеть, соединения не освобождались. После ввода defer всё работало корректно: ресурсы закрывались всегда.
История
Разработчик пытался положиться на defer для освобождения глобального состояния. При возникновении fatalError ресурс не освобождался, что приводило к блокировкам сервисов и необходимости рестарта.
История
В функции объявили несколько defer, полагая, что они выполнятся в порядке объявления. В результате ресурсы закрывались в неверном порядке (например, сначала закрылся file descriptor, а потом к нему пытались обращаться). Решение: помнить о LIFO-порядке выполнения defer-блоков.