🔥 정리 동작 지정하기
defer
문을 사용하면 현재 코드 블록을 떠나기 직전에 실행할 일련의 문장을 지정할 수 있습니다. 이 defer
문은 오류가 던져져서 떠나든, return
이나 break
같은 문으로 떠나든 상관없이, 현재 코드 블록을 어떻게
떠나든지 수행해야 할 필요한 정리를 할 수 있게 해줍니다. 예를 들어, defer
문을 사용하여 파일 디스크립터가 닫히고 수동으로 할당된 메모리가 해제되도록 보장할 수 있습니다.
defer
문은 현재 범위를 빠져나갈 때까지 실행을 미룹니다. 이 문은 defer
키워드와 나중에 실행될 문장들로 구성됩니다. 미뤄진 문장들은 break
나 return
문, 또는 오류를 던져서 문장들 밖으로 제어를 전달하는 어떤 코드도 포함할 수 없습니다. 미뤄진 동작들은 소스 코드에 작성된 순서의 역순으로 실행됩니다. 즉, 첫 번째 defer
문의 코드가 마지막에 실행되고, 두 번째 defer
문의 코드가 끝에서 두 번째로 실행되는 식이죠. 소스 코드 순서상 마지막 defer
문이 가장 먼저 실행됩니다.
func processFile(filename: String) throws { if exists(filename) { let file = open(filename) defer { close(file) // 범위가 끝날 때 실행됩니다. } while let line = try file.readline() { // 파일을 처리합니다. } // close(file)이 여기, 범위의 끝에서 호출됩니다. } }
swift
위 예제는 defer
문을 사용하여 open(_:)
함수에 대응하는 close(_:)
호출이 있음을 보장합니다.
오류 처리 코드가 없는 경우에도 defer
문을 사용할 수 있습니다. 이는 함수의 여러 반환 지점에서 공통적으로 실행되어야 하는 정리 코드가 있을 때 특히 유용합니다.
다음은 defer
를 사용하는 또 다른 예시입니다. 이 코드는 데이터베이스 연결을 열고, 일부 작업을 수행한 후, 연결을 닫습니다.
func performDatabaseOperation() throws { let db = openDatabase() defer { closeDatabase(db) // 함수가 어떻게 종료되든 실행됩니다. } try db.executeQuery("INSERT INTO ...") try db.executeQuery("UPDATE ...") try db.executeQuery("DELETE FROM ...") // closeDatabase(db)는 여기서 호출됩니다. }
swift
이 예시에서, closeDatabase(_:)
호출은 defer
블록에 들어가 있습니다. 이는 performDatabaseOperation()
함수가 정상적으로 종료되든, throw
를 통해 빠르게 종료되든 상관없이 항상 데이터베이스 연결이 닫힘을 보장합니다.
defer
의 또 다른 일반적인 사용 사례는 잠금(lock)을 획득하고 해제하는 것입니다. 다음은 defer
를 사용하여 잠금을 안전하게 관리하는 방법을 보여주는 예시입니다:
func syncronizedOperation(lock: Lock, closure: () throws -> Void) rethrows { lock.lock() defer { lock.unlock() // 함수가 어떻게 종료되든 잠금을 해제합니다. } try closure() }
swift
이 함수는 잠금을 획득하고, defer
를 사용하여 함수가 종료되기 전에 잠금이 항상 해제되도록 합니다. 그런 다음 제공된 클로저를 실행합니다. 클로저가 오류를 던지면, 잠금은 여전히 defer
블록에 의해 해제되고, 오류는 함수에 의해 다시 던져집니다(rethrows
키워드 덕분에).
defer
는 강력하고 유용한 기능이지만, 주의해서 사용해야 합니다. defer
블록은 함수의 흐름을 복잡하게 만들 수 있고, 특히 여러 개의 defer
블록이 있을 때는 더욱 그렇습니다. 따라서 defer
는 필요한 경우에만, 그리고 코드의 명확성을 해치지 않는 방식으로 사용되어야 합니다.
defer
의 또 다른 주의사항은 성능과 관련이 있습니다. defer
블록은 함수의 종료 시점까지 메모리에 유지되므로, 많은 수의 defer
블록을 사용하면 불필요한 오버헤드가 발생할 수 있습니다.
그럼에도 불구하고, defer
는 Swift의 오류 처리와 리소스 관리 능력을 크게 향상시키는 매우 유용한 도구입니다. 파일 핸들 닫기, 잠금 해제, 메모리 해제 등 정리 작업을 보장하는 데 defer
를 활용하면 더 강건하고 안전한 코드를 작성할 수 있습니다.