defer는 Swift의 특별한 구성으로, 함수의 범위에서 나가기 직전에 특정 코드 블록을 실행할 수 있도록 하며, 일반적인 return이나 오류(throw)로 인해 나가는 경우와 관계없이 작동합니다. defer는 리소스를 해제하거나 변경을 취소 할 때 или 작업을 마무리할 때 유용하게 사용할 수 있습니다.
작동의 특징:
예제:
func testDefer() { print("시작") defer { print("첫 번째 defer") } defer { print("두 번째 defer") } print("종료") } // 출력: // 시작 // 종료 // 두 번째 defer // 첫 번째 defer
경계 사례:
함수 내에서 fatalError가 호출되면 모든 defer 블록이 실행되나요?
답변: 아니요, 함수에서 fatalError(또는 유사한 제어 불가능한 크래시)가 호출되면, 모든 defer 블록이 실행되지 않습니다. defer는 애플리케이션이 비정상적으로 종료되는 경우 코드가 호출될 것이라는 보장을 제공하지 않습니다.
예제:
func foo() { defer { print("Defer 1") } fatalError("어이구") defer { print("Defer 2") } } foo() // 아무것도 출력되지 않으며 크래시가 발생합니다.
이야기
프로젝트에서 파일 디스크립터를 닫기 위해 defer를 사용했습니다. 오류가 발생했을 때 fatalError를 사용했으며, 이는 리소스가 누출되는 결과를 초래했습니다. 왜냐하면 크래시 시 defer가 실행되지 않았기 때문입니다.
이야기
하나의 함수에서 여러 defer가 있었으며, 그 중 일부는 지역 변수의 상태에 의존했습니다. 개발자는 변수가 특정 값일 것이라고 예상했으나, defer에서 이 값이 다른 코드 섹션에 의해 변경되었고, defer 실행 시 актуальное 값이 사용되었으며, 그 결과 필요하지 않은 ID로 트랜잭션 취소 버그가 발생했습니다.
이야기
중첩된 closure에서 defer 블록을 작성했으며, 그것이 외부 함수에서 나갈 때 실행될 것이라고 생각했습니다. 결과적으로 이 defer는 closure에서 나갈 때 실행되었고, 전체 함수에서 나가는 것이 아니라 리소스가 너무 일찍 해제되었습니다.