defer

이원희·2021년 1월 11일
0

 🐧 Swift

목록 보기
18/32
post-thumbnail

오늘은 코드를 보다 첨 보는 구문이 있어서 정리해봤다.

defer

defer는 클로저 안에서 현재 스코프의 맨 끝에 실행되어야 하는 코드 일부를 넣어서 사용한다.
현재 코드 블록을 나가기 전에 꼭 실행해야 되는 코드를 작성하여 코드가 블록을 어떻게 빠져 나가든 꼭 마무리해야 되는 작업을 할 수 있도록 한다.

func deferTest() {
    defer {
        print("this is defer")
    }
    print("one two three")
}

deferTest()

이런 코드를 작성하면

one two three
this is defer

라는 결과를 받을 수 있다.


defer 실행 순서

그렇다면 defer가 여러개라면 어떻게 될까?

func deferTest() {
    defer {
        print("defer 1")
    }
    
    defer {
        print("defer 2")
    }
    
    defer {
        print("defer 3")
    }
    
    print("one two three")
}

deferTest()

defer 3개를 사용해서 코드를 써봤다.

one two three
defer 3
defer 2
defer 1

defer들이 작성된 순서의 역순으로 호출되는 것을 볼 수 있다.


중첩 코드에서의 실행 순서

func deferTest() {
    defer {
        print("deferTest first defer")
    }
    
    for i in 0..<2 {
        defer {
            print("for defer")
        }
        print("This is a for \(i)")
    }
    
    defer {
        print("deferTest last defer")
    }
}

deferTest()

위와 같이 중첩된 코드에서 defer는 어떻게 실행될까?

우선 defer의 특징을 생각해보자.

  • defer가 여러 개일때 작성된 순서의 역순으로 실행된다.
  • defer선언된 코드 블록을 빠져나가기 직전에 실행된다.
This is a for 0
for defer
This is a for 1
for defer
deferTest last defer
deferTest first defer

위와 같은 결과를 출력한다.

for문은 루프가 끝날 때마다 defer가 호출된다.


throw와 defer

그렇다면 throwdefer를 같이 쓰면 어떻게 될까?

func throwDeferTest(isError: Bool) throws -> Void {
    defer {
        print("This is defer")
    }
    
    if isError {
        enum DeferError: Error {
            case error
        }
        
        throw DeferError.error
    }
    
    defer {
        print("This is last defer")
    }
    
    print("end func")
}

print("==error: true==")
try? throwDeferTest(isError: true)
print("==error: false==")
try? throwDeferTest(isError: false)

isErrortrue라면 에러를 던지게 된다.

==error: true==
This is defer
==error: false==
end func
This is last defer
This is defer

중간에 throw가 발생해서 함수가 종료될 경우 throw 코드 아래에 선언된 defer에 도달하지 못한다.
따라서 함수가 종료 되어도 throw 코드 아래에 선언한 defer는 호출되지 않는다.


guard와 defer

guarddefer를 같이 쓰면 어떻게 될까?

func guardDeferTest(_ number: Int?) {
    defer {
        print("This is Top defer")
    }
    
    guard let n = number else {
        return
    }
    
    defer {
        print("This is end defer")
    }
    
    print("end func")
}

print("==not optional number==")
guardDeferTest(1)
print("==optional number==")
guardDeferTest(nil)

guard문으로 number가 nil일때에는 return 하도록 했다.

==not optional number==
end func
This is end defer
This is Top defer
==optional number==
This is Top defer

throwdefer를 같이 썼을때와 똑같은 결과를 출력한다.

0개의 댓글