defer 연산자는 현재의 범위를 벗어날 때까지 코드의 실행을 미룹니다. 일반적으로 함수에서 사용됩니다. 자원 정리, 파일 닫기 및 메모리 해제를 위해 편리하며, 이를 자동화된 정리(cleanup)라고 합니다.
특징:
예제:
func processFile() { let file = openFile() defer { closeFile(file) } // 파일 작업 // throw 또는 return의 경우에도 file은 닫힙니다. }
비정상적인 사용: 'finally'와 같은 구조를 부분적으로 모방하거나, 로그 및 실행 시간을 추적하기 위한 코드를 그룹화합니다.
함수 실행 도중 애플리케이션이 종료되면 defer가 실행될까요?
— 아닙니다. Defer는 정상적으로 범위를 종료할 때만 실행됩니다 (return, throw 또는 정상 종료). 애플리케이션이 강제로 종료되면 (예: SIGKILL 신호 또는 fatalError로 인해) defer 블록은 실행될 시간이 없습니다.
예제:
func foo() { defer { print("정리") } fatalError("충돌!") // defer는 실행되지 않습니다. }
이야기
소켓 작업을 수행하는 함수가 throw 발생 시 연결을 정리하지 않았습니다. 데이터가 남아 있었고, 연결이 해제되지 않았습니다. defer를 사용하니 모든 것이 정상적으로 작동했습니다: 자원이 항상 닫혔습니다.
이야기
개발자가 글로벌 상태 해제에 대해 defer에 의존하려고 했습니다. fatalError가 발생했을 때 자원이 해제되지 않아 서비스가 잠기고 재시작이 필요했습니다.
이야기
함수에서 여러 defer를 선언하고 그것들이 선언된 순서로 실행될 것이라고 믿었습니다. 결과적으로 자원이 잘못된 순서로 닫혔습니다 (예: 먼저 파일 설명자가 닫히고 나중에 이에 접근하려고 했습니다). 해결책: defer 블록의 LIFO 실행 순서를 기억하는 것입니다.