История вопроса:
Defer был добавлен в Swift (вдохновлённый аналогами в Go, C#) для гарантированной очистки ресурсов даже при возникновении ошибок, выходе из функции или при возврате значений из разных точек функций.
Проблема:
Преждевременное освобождение, забытые чистки ресурсов (например, закрытие файлов, логирование, rollback транзакций). Иногда путают порядок исполнения, ошибочно полагая, что defer выполняется в момент объявления.
Решение:
Defer — это специальный блок, который откладывает выполнение кода до конца текущей области (scope), обычно функции. Все defer выполняются в обратном порядке размещения (LIFO). Это позволяет централизованно управлять очисткой ресурсов, освобождением памяти или откатом транзакций.
Пример кода:
func processFile() { let file = File("/tmp/data.txt") file.open() defer { file.close() print("File closed") } // Работа с файлом print("Reading data…") }
Ключевые особенности:
Выполняется ли код внутри defer при падении приложения (crash) до выхода из функции?
Нет, код defer исполняется только при корректном выходе из области видимости (scope). Если приложение завершилось аварийно (например, fatal error), defer не выполнится.
Можно ли использовать return внутри defer?
Нет, нельзя. Defer блок не допускает возврат значений или завершение области, только инструкции.
Может ли defer использоваться для модификации переменных, объявленных до defer?
Да, defer захватывает значения с текущего стека в момент исполнения. Можно изменять значения, объявленные до defer, и они сохранятся при выходе из scope.
Пример кода:
func example() -> Int { var result = 0 defer { result = 42 } return result // defer выполнится, результат — 42 }
Файл открывается, но закрывается только явно в самом низу функции, а при ошибках или раннем выходе из функции файл остаётся открытым.
Плюсы:
Минусы:
Использование defer для закрытия файла сразу после открытия. Даже если возникнет исключение или возврат из функции, файл гарантированно закроется.
Плюсы:
Минусы: