티스토리 뷰

iOS

[Swift] defer 구문

Sueaty 2021. 1. 16. 02:00

이 글은 defer 구문에 대해 다루겠습니다. Swift Programming Language, 야곰님의 스위프트 프로그래밍 3판, 숩님 블로그와 프로젝트 경험을 바탕으로 정리하는 글이라 오류가 있을 수 있습니다. 오류 발견 시 댓글로 꼭 말씀해주세요! 시작해볼까요?

defer 구문

defer 구문이 하는 역할에 대한 궁금증은 단어 자체의 뜻을 알면 많은 부분 해소된다고 생각합니다.

 

미루다, 연기하다라죠? 맞습니다. defer 구문은 실행을 잠시 미뤄두었다가 실행되니까요. 공식 문서로 명확히 해보겠습니다.

A defer statement is used for executing code just before transferring program control
outside of the scope that the defer statement appears in.

defer 구문은 자신이 속해있는 코드 블럭의 scope에서 빠져나가기 '직전' 에 실행되는 구문입니다.

scope는 함수, 조건문, 반복문, do-try-catch문 등의 scope을 모두 뜻하고 빠져나간다는 것은 정상 종료를 뜻할수도 있고 에러를 만나 비정상 종료가 될 수도 있다는 뜻입니다. 하지만 어떤 종료를 하던 무관하게 빠져나가기 직전에 defer문 내부의 코드를 실행하고 종료하는 것입니다.

어떤 형태로 빠져나가도 반드시 실행이 보장되어 있는 구문이라서 오류처리를 할 때 유용하게 쓰입니다. 2가지 예시를 통해 알아보도록 하겠습니다.


파일 handling

아래 코드는 Network의 상태 메세지를 가져와서 정상("Success")이 아닐 경우 상태 메세지를 파일에 write하는 코드입니다.

func logErrorMessage() {
   let file = openFile(...)
   defer { file.close() }

   guard let statusMessage = fetchNetworkStatus() where statusMessage != "Success" { 
      return 
   }

   file.write(statusMessage)

}

물론 파일에 읽고 쓰기를 하려면 파일을 열어야겠고, 필요한 동작을 다 했으면 파일을 안전하게 닫아야 합니다.

파일을 닫는 코드가 defer block 안에 있기 때문에 logErrorMessage 함수가 종료되기 직전에 실행이 될텐데,
else 문으로 종료될 때, 또는 정상 실행 후 마지막에 불릴 수도 있습니다. 어떤 종료건 파일은 무조건 닫아야 하니 defer에 넣은 것입니다.

위 코드에서는 guard 문이 하나지만 그 외의 빠른 종료 또는 error handling이 들어간다면 항상 file.close()를 해주는 것이 번거로울 수 있죠.그러나 defer statement로 코드가 많이 간결해졌습니다.

두번째 예시를 보면서 defer의 특징을 조금 더 살펴보도록 하겠습니다.


Defer의 특징

do-try-catch 문에서 무조건 catch 문으로 넘어가게 하는 코드입니다.

do {
    defer { print("1") }
    defer { print("2") }
    try fail()
    print("do-statement finished")
} catch  {
    print("catch statement")
} 

// 무조건 Error가 발생
func fail() throws -> () {
    throw NSError(domain: "U", code: 1, userInfo: nil)
}

fail 함수를 실행 위쪽을 보면 2개의 defer block이 있습니다. 즉, try fail()을 통해 error가 발생한다면 catch문으로 넘어갈텐데,

그 전에 defer block을 실행하게 됩니다. 만약 try가 무탈하게 지나간다면 "do-statement finished"가 불리고 defer가 불리겠죠?

정리를 해보면,

  1. try 실패
2
1
catch statement
  1. try 성공 (물론 위 코드에서는 이렇게 나올 수 없습니다)
do-statement finished
2
1

우리는 결과를 보고 defer의 특징을 알 수 있습니다.

  1. (당연) scope를 빠져나가기 직전에 실행 됨
  2. 정의 된 역순으로 실행 됨

defer Warning

처음에 defer문을 사용할 때 함수가 종료되면 무조건 불리는 것인 줄 알고 아래와 같이 코드를 작성한 적이 있습니다.

func printUsingDefer() {
   print("A")
   defer { print("function finished") }
}

지금 보면 좀 민망한 코드긴 하지만... 위와 같이 코드를 쓰면 'defer' statement before end of scope always executes immediately; replace with 'do' statement to silence this warning 와 같은 warning message가 뜹니다. 사실 당연한 메세지인데, defer가 맨 뒤에 있으면 어차피 실행이 되는 것이기 때문입니다. 그러니 defer를 쓸 때는 현재 scope 실행이 끝날 때 반드시 처리를 해야하는(오류 처리, 안전하게 리소스 닫기) 작업이 있는지 보고 작성하면 될 것 같습니다.

'iOS' 카테고리의 다른 글

[iOS] AppDelegate & SceneDelegate  (2) 2021.01.17
[iOS] SceneDelegate & AppDelegate의 역할  (0) 2021.01.16
[Swift] Optional  (0) 2021.01.12
[Swift] Optional  (0) 2021.01.12
[iOS] URLSession을 이용해 서버로부터 JSON 데이터 받아오기  (0) 2021.01.06
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함